blob: 7534e3a2bf40f400dc4396d4f8a3e0b4a16e7dfa [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
Sora Su06eadd02025-05-27 11:28:51 +08001558LIBPLDM_ABI_TESTING
1559int encode_request_downstream_device_update_req(
1560 uint8_t instance_id,
1561 const struct pldm_request_downstream_device_update_req *req_data,
1562 struct pldm_msg *msg, size_t *payload_length)
1563{
1564 PLDM_MSGBUF_DEFINE_P(buf);
1565 int rc;
1566
1567 if (!req_data || !msg || !payload_length ||
1568 req_data->maximum_downstream_device_transfer_size <
1569 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1570 req_data->maximum_outstanding_transfer_requests <
1571 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1572 return -EINVAL;
1573 }
1574
1575 rc = encode_pldm_header_only_errno(
1576 PLDM_REQUEST, instance_id, PLDM_FWUP,
1577 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1578 if (rc) {
1579 return rc;
1580 }
1581
1582 rc = pldm_msgbuf_init_errno(buf,
1583 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1584 msg->payload, *payload_length);
1585 if (rc) {
1586 return rc;
1587 }
1588
1589 pldm_msgbuf_insert(buf,
1590 req_data->maximum_downstream_device_transfer_size);
1591 pldm_msgbuf_insert(buf,
1592 req_data->maximum_outstanding_transfer_requests);
1593 pldm_msgbuf_insert(buf,
1594 req_data->downstream_device_package_data_length);
1595
1596 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1597}
1598
1599LIBPLDM_ABI_TESTING
1600int decode_request_downstream_device_update_req(
1601 const struct pldm_msg *msg, size_t payload_length,
1602 struct pldm_request_downstream_device_update_req *req)
1603{
1604 int rc;
1605 PLDM_MSGBUF_DEFINE_P(buf);
1606
1607 if (!msg || !req) {
1608 return -EINVAL;
1609 }
1610
1611 rc = pldm_msgbuf_init_errno(buf,
1612 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1613 msg->payload, payload_length);
1614 if (rc) {
1615 return rc;
1616 }
1617
1618 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1619 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1620 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1621
1622 return pldm_msgbuf_complete_consumed(buf);
1623}
1624
1625LIBPLDM_ABI_TESTING
1626int encode_request_downstream_device_update_resp(
1627 uint8_t instance_id,
1628 const struct pldm_request_downstream_device_update_resp *resp_data,
1629 struct pldm_msg *msg, size_t *payload_length)
1630{
1631 PLDM_MSGBUF_DEFINE_P(buf);
1632 int rc;
1633
1634 if (!resp_data || !msg || !payload_length) {
1635 return -EINVAL;
1636 }
1637
1638 rc = encode_pldm_header_only_errno(
1639 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1640 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1641 if (rc) {
1642 return rc;
1643 }
1644
1645 rc = pldm_msgbuf_init_errno(
1646 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1647 *payload_length);
1648 if (rc) {
1649 return rc;
1650 }
1651
1652 pldm_msgbuf_insert(buf, resp_data->completion_code);
1653 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1654 pldm_msgbuf_insert(
1655 buf, resp_data->downstream_device_will_send_get_package_data);
1656 pldm_msgbuf_insert(buf,
1657 resp_data->get_package_data_maximum_transfer_size);
1658
1659 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1660}
1661
1662LIBPLDM_ABI_TESTING
1663int decode_request_downstream_device_update_resp(
1664 const struct pldm_msg *msg, size_t payload_length,
1665 struct pldm_request_downstream_device_update_resp *resp_data)
1666{
1667 PLDM_MSGBUF_DEFINE_P(buf);
1668 int rc;
1669
1670 if (!msg || !resp_data) {
1671 return -EINVAL;
1672 }
1673
1674 rc = pldm_msg_has_error(msg,
1675 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
1676 if (rc) {
1677 resp_data->completion_code = rc;
1678 return 0;
1679 }
1680
1681 rc = pldm_msgbuf_init_errno(
1682 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1683 payload_length);
1684 if (rc) {
1685 return rc;
1686 }
1687
1688 pldm_msgbuf_extract(buf, resp_data->completion_code);
1689 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
1690 pldm_msgbuf_extract(
1691 buf, resp_data->downstream_device_will_send_get_package_data);
1692 pldm_msgbuf_extract(buf,
1693 resp_data->get_package_data_maximum_transfer_size);
1694
1695 return pldm_msgbuf_complete_consumed(buf);
1696}
1697
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301698LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301699int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1700 uint16_t num_of_comp,
1701 uint8_t max_outstanding_transfer_req,
1702 uint16_t pkg_data_len,
1703 uint8_t comp_image_set_ver_str_type,
1704 uint8_t comp_image_set_ver_str_len,
1705 const struct variable_field *comp_img_set_ver_str,
1706 struct pldm_msg *msg, size_t payload_length)
1707{
1708 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1709 msg == NULL) {
1710 return PLDM_ERROR_INVALID_DATA;
1711 }
1712
1713 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301714 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301715 return PLDM_ERROR_INVALID_LENGTH;
1716 }
1717
1718 if ((comp_image_set_ver_str_len == 0) ||
1719 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1720 return PLDM_ERROR_INVALID_DATA;
1721 }
1722
1723 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1724 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1725 return PLDM_ERROR_INVALID_DATA;
1726 }
1727
1728 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1729 return PLDM_ERROR_INVALID_DATA;
1730 }
1731
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301732 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301733 header.instance = instance_id;
1734 header.msg_type = PLDM_REQUEST;
1735 header.pldm_type = PLDM_FWUP;
1736 header.command = PLDM_REQUEST_UPDATE;
1737 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1738 if (rc) {
1739 return rc;
1740 }
1741
1742 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301743 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301744
1745 request->max_transfer_size = htole32(max_transfer_size);
1746 request->num_of_comp = htole16(num_of_comp);
1747 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1748 request->pkg_data_len = htole16(pkg_data_len);
1749 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1750 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1751
1752 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1753 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1754
1755 return PLDM_SUCCESS;
1756}
1757
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001758LIBPLDM_ABI_TESTING
1759int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1760 struct pldm_request_update_req_full *req)
1761{
1762 int rc;
1763 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301764 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001765
1766 if (msg == NULL || req == NULL) {
1767 return -EINVAL;
1768 }
1769
1770 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1771 if (rc) {
1772 return rc;
1773 }
1774
1775 pldm_msgbuf_extract(buf, req->max_transfer_size);
1776 pldm_msgbuf_extract(buf, req->num_of_comp);
1777 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
1778 pldm_msgbuf_extract(buf, req->pkg_data_len);
1779 rc = pldm_msgbuf_extract(buf, t);
1780 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301781 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001782 }
1783 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301784 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001785 }
1786 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
1787 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
1788 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301789 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001790 }
1791
1792 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
1793 req->image_set_ver.str_data,
1794 PLDM_FIRMWARE_MAX_STRING);
1795 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301796 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001797 }
1798
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301799 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001800}
1801
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301802LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301803int decode_request_update_resp(const struct pldm_msg *msg,
1804 size_t payload_length, uint8_t *completion_code,
1805 uint16_t *fd_meta_data_len,
1806 uint8_t *fd_will_send_pkg_data)
1807{
1808 if (msg == NULL || completion_code == NULL ||
1809 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
1810 !payload_length) {
1811 return PLDM_ERROR_INVALID_DATA;
1812 }
1813
1814 *completion_code = msg->payload[0];
1815 if (*completion_code != PLDM_SUCCESS) {
1816 return PLDM_SUCCESS;
1817 }
1818
1819 if (payload_length != sizeof(struct pldm_request_update_resp)) {
1820 return PLDM_ERROR_INVALID_LENGTH;
1821 }
1822
1823 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301824 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301825
1826 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
1827 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
1828
1829 return PLDM_SUCCESS;
1830}
1831
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001832LIBPLDM_ABI_TESTING
1833int encode_request_update_resp(uint8_t instance_id,
1834 const struct pldm_request_update_resp *resp_data,
1835 struct pldm_msg *msg, size_t *payload_length)
1836{
Andrew Jefferya1896962025-03-03 21:41:25 +10301837 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001838 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001839
1840 if (msg == NULL || payload_length == NULL) {
1841 return -EINVAL;
1842 }
1843
1844 struct pldm_header_info header = {
1845 .instance = instance_id,
1846 .msg_type = PLDM_RESPONSE,
1847 .pldm_type = PLDM_FWUP,
1848 .command = PLDM_REQUEST_UPDATE,
1849 };
1850 rc = pack_pldm_header(&header, &(msg->hdr));
1851 if (rc) {
1852 return -EINVAL;
1853 }
1854
1855 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1856 if (rc) {
1857 return rc;
1858 }
1859
1860 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1861 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
1862 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
1863
1864 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
1865
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301866 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001867}
1868
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301869LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301870int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
1871 uint16_t comp_classification,
1872 uint16_t comp_identifier,
1873 uint8_t comp_classification_index,
1874 uint32_t comp_comparison_stamp,
1875 uint8_t comp_ver_str_type,
1876 uint8_t comp_ver_str_len,
1877 const struct variable_field *comp_ver_str,
1878 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301879{
1880 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1881 return PLDM_ERROR_INVALID_DATA;
1882 }
1883
1884 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301885 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301886 return PLDM_ERROR_INVALID_LENGTH;
1887 }
1888
1889 if ((comp_ver_str_len == 0) ||
1890 (comp_ver_str_len != comp_ver_str->length)) {
1891 return PLDM_ERROR_INVALID_DATA;
1892 }
1893
1894 if (!is_transfer_flag_valid(transfer_flag)) {
1895 return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
1896 }
1897
1898 if (!is_string_type_valid(comp_ver_str_type)) {
1899 return PLDM_ERROR_INVALID_DATA;
1900 }
1901
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301902 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301903 header.instance = instance_id;
1904 header.msg_type = PLDM_REQUEST;
1905 header.pldm_type = PLDM_FWUP;
1906 header.command = PLDM_PASS_COMPONENT_TABLE;
1907 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1908 if (rc) {
1909 return rc;
1910 }
1911
1912 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301913 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301914
1915 request->transfer_flag = transfer_flag;
1916 request->comp_classification = htole16(comp_classification);
1917 request->comp_identifier = htole16(comp_identifier);
1918 request->comp_classification_index = comp_classification_index;
1919 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1920 request->comp_ver_str_type = comp_ver_str_type;
1921 request->comp_ver_str_len = comp_ver_str_len;
1922
1923 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
1924 comp_ver_str->ptr, comp_ver_str->length);
1925
1926 return PLDM_SUCCESS;
1927}
1928
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001929LIBPLDM_ABI_TESTING
1930int decode_pass_component_table_req(
1931 const struct pldm_msg *msg, size_t payload_length,
1932 struct pldm_pass_component_table_req_full *pcomp)
1933{
1934 int rc;
1935 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301936 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001937
1938 if (msg == NULL || pcomp == NULL) {
1939 return -EINVAL;
1940 }
1941
1942 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1943 if (rc) {
1944 return rc;
1945 }
1946
1947 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
1948 pldm_msgbuf_extract(buf, pcomp->comp_classification);
1949 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
1950 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
1951 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
1952 rc = pldm_msgbuf_extract(buf, t);
1953 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301954 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001955 }
1956 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301957 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001958 }
1959 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
1960 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
1961 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301962 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001963 }
1964 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
1965 pcomp->version.str_data,
1966 PLDM_FIRMWARE_MAX_STRING);
1967 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301968 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001969 }
1970
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301971 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001972}
1973
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301974LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301975int decode_pass_component_table_resp(const struct pldm_msg *msg,
1976 const size_t payload_length,
1977 uint8_t *completion_code,
1978 uint8_t *comp_resp,
1979 uint8_t *comp_resp_code)
1980{
1981 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
1982 comp_resp_code == NULL || !payload_length) {
1983 return PLDM_ERROR_INVALID_DATA;
1984 }
1985
1986 *completion_code = msg->payload[0];
1987 if (*completion_code != PLDM_SUCCESS) {
1988 return PLDM_SUCCESS;
1989 }
1990
1991 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
1992 return PLDM_ERROR_INVALID_LENGTH;
1993 }
1994
1995 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301996 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301997
1998 if (!is_comp_resp_valid(response->comp_resp)) {
1999 return PLDM_ERROR_INVALID_DATA;
2000 }
2001
2002 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2003 return PLDM_ERROR_INVALID_DATA;
2004 }
2005
2006 *comp_resp = response->comp_resp;
2007 *comp_resp_code = response->comp_resp_code;
2008
2009 return PLDM_SUCCESS;
2010}
2011
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002012LIBPLDM_ABI_TESTING
2013int encode_pass_component_table_resp(
2014 uint8_t instance_id,
2015 const struct pldm_pass_component_table_resp *resp_data,
2016 struct pldm_msg *msg, size_t *payload_length)
2017{
Andrew Jefferya1896962025-03-03 21:41:25 +10302018 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002019 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002020
2021 if (msg == NULL || payload_length == NULL) {
2022 return -EINVAL;
2023 }
2024
2025 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2026 PLDM_PASS_COMPONENT_TABLE, msg);
2027 if (rc) {
2028 return -EINVAL;
2029 }
2030
2031 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2032 if (rc) {
2033 return rc;
2034 }
2035
2036 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2037 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2038 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2039
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302040 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002041}
2042
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302043LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302044int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302045 uint8_t instance_id, uint16_t comp_classification,
2046 uint16_t comp_identifier, uint8_t comp_classification_index,
2047 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2048 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2049 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2050 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302051{
2052 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2053 return PLDM_ERROR_INVALID_DATA;
2054 }
2055
2056 if (payload_length !=
2057 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2058 return PLDM_ERROR_INVALID_LENGTH;
2059 }
2060
2061 if (!comp_image_size) {
2062 return PLDM_ERROR_INVALID_DATA;
2063 }
2064
2065 if ((comp_ver_str_len == 0) ||
2066 (comp_ver_str_len != comp_ver_str->length)) {
2067 return PLDM_ERROR_INVALID_DATA;
2068 }
2069
2070 if (!is_string_type_valid(comp_ver_str_type)) {
2071 return PLDM_ERROR_INVALID_DATA;
2072 }
2073
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302074 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302075 header.instance = instance_id;
2076 header.msg_type = PLDM_REQUEST;
2077 header.pldm_type = PLDM_FWUP;
2078 header.command = PLDM_UPDATE_COMPONENT;
2079 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2080 if (rc) {
2081 return rc;
2082 }
2083
2084 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302085 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302086
2087 request->comp_classification = htole16(comp_classification);
2088 request->comp_identifier = htole16(comp_identifier);
2089 request->comp_classification_index = comp_classification_index;
2090 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2091 request->comp_image_size = htole32(comp_image_size);
2092 request->update_option_flags.value = htole32(update_option_flags.value);
2093 request->comp_ver_str_type = comp_ver_str_type;
2094 request->comp_ver_str_len = comp_ver_str_len;
2095
2096 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2097 comp_ver_str->ptr, comp_ver_str->length);
2098
2099 return PLDM_SUCCESS;
2100}
2101
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002102LIBPLDM_ABI_TESTING
2103int decode_update_component_req(const struct pldm_msg *msg,
2104 size_t payload_length,
2105 struct pldm_update_component_req_full *up)
2106{
2107 int rc;
2108 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302109 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002110
2111 if (msg == NULL || up == NULL) {
2112 return -EINVAL;
2113 }
2114
2115 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2116 if (rc) {
2117 return rc;
2118 }
2119
2120 pldm_msgbuf_extract(buf, up->comp_classification);
2121 pldm_msgbuf_extract(buf, up->comp_identifier);
2122 pldm_msgbuf_extract(buf, up->comp_classification_index);
2123 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2124 pldm_msgbuf_extract(buf, up->comp_image_size);
2125 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2126 rc = pldm_msgbuf_extract(buf, t);
2127 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302128 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002129 }
2130 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302131 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002132 }
2133 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2134 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2135 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302136 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002137 }
2138 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2139 up->version.str_data,
2140 PLDM_FIRMWARE_MAX_STRING);
2141 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302142 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002143 }
2144
Andrew Jefferya1896962025-03-03 21:41:25 +10302145 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002146}
2147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302149int decode_update_component_resp(const struct pldm_msg *msg,
2150 size_t payload_length,
2151 uint8_t *completion_code,
2152 uint8_t *comp_compatibility_resp,
2153 uint8_t *comp_compatibility_resp_code,
2154 bitfield32_t *update_option_flags_enabled,
2155 uint16_t *time_before_req_fw_data)
2156{
2157 if (msg == NULL || completion_code == NULL ||
2158 comp_compatibility_resp == NULL ||
2159 comp_compatibility_resp_code == NULL ||
2160 update_option_flags_enabled == NULL ||
2161 time_before_req_fw_data == NULL || !payload_length) {
2162 return PLDM_ERROR_INVALID_DATA;
2163 }
2164
2165 *completion_code = msg->payload[0];
2166 if (*completion_code != PLDM_SUCCESS) {
2167 return PLDM_SUCCESS;
2168 }
2169
2170 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2171 return PLDM_ERROR_INVALID_LENGTH;
2172 }
2173
2174 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302175 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302176
2177 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302178 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302179 return PLDM_ERROR_INVALID_DATA;
2180 }
2181
2182 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302183 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302184 return PLDM_ERROR_INVALID_DATA;
2185 }
2186
2187 *comp_compatibility_resp = response->comp_compatibility_resp;
2188 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2189 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302190 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302191 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2192
2193 return PLDM_SUCCESS;
2194}
2195
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002196LIBPLDM_ABI_TESTING
2197int encode_update_component_resp(
2198 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2199 struct pldm_msg *msg, size_t *payload_length)
2200{
Andrew Jefferya1896962025-03-03 21:41:25 +10302201 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002202 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002203
2204 if (msg == NULL || payload_length == NULL) {
2205 return -EINVAL;
2206 }
2207
2208 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2209 PLDM_UPDATE_COMPONENT, msg);
2210 if (rc) {
2211 return -EINVAL;
2212 }
2213
2214 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2215 if (rc) {
2216 return rc;
2217 }
2218
2219 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2220 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2221 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2222 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2223 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2224
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302225 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002226}
2227
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302228LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302229int decode_request_firmware_data_req(const struct pldm_msg *msg,
2230 size_t payload_length, uint32_t *offset,
2231 uint32_t *length)
2232{
2233 if (msg == NULL || offset == NULL || length == NULL) {
2234 return PLDM_ERROR_INVALID_DATA;
2235 }
2236 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2237 return PLDM_ERROR_INVALID_LENGTH;
2238 }
2239 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302240 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302241 *offset = le32toh(request->offset);
2242 *length = le32toh(request->length);
2243
2244 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2245 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2246 }
2247
2248 return PLDM_SUCCESS;
2249}
2250
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002251LIBPLDM_ABI_TESTING
2252int encode_request_firmware_data_req(
2253 uint8_t instance_id,
2254 const struct pldm_request_firmware_data_req *req_params,
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_REQUEST_FIRMWARE_DATA, 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
2275 pldm_msgbuf_insert(buf, req_params->offset);
2276 pldm_msgbuf_insert(buf, req_params->length);
2277
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302278 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002279}
2280
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302281LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302282int encode_request_firmware_data_resp(uint8_t instance_id,
2283 uint8_t completion_code,
2284 struct pldm_msg *msg,
2285 size_t payload_length)
2286{
2287 if (msg == NULL || !payload_length) {
2288 return PLDM_ERROR_INVALID_DATA;
2289 }
2290
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302291 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302292 header.instance = instance_id;
2293 header.msg_type = PLDM_RESPONSE;
2294 header.pldm_type = PLDM_FWUP;
2295 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2296 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2297 if (rc) {
2298 return rc;
2299 }
2300
2301 msg->payload[0] = completion_code;
2302
2303 return PLDM_SUCCESS;
2304}
2305
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302306LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302307int decode_transfer_complete_req(const struct pldm_msg *msg,
2308 size_t payload_length,
2309 uint8_t *transfer_result)
2310{
2311 if (msg == NULL || transfer_result == NULL) {
2312 return PLDM_ERROR_INVALID_DATA;
2313 }
2314
2315 if (payload_length != sizeof(*transfer_result)) {
2316 return PLDM_ERROR_INVALID_LENGTH;
2317 }
2318
2319 *transfer_result = msg->payload[0];
2320 return PLDM_SUCCESS;
2321}
2322
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002323LIBPLDM_ABI_TESTING
2324int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2325 struct pldm_msg *msg, size_t *payload_length)
2326{
Andrew Jefferya1896962025-03-03 21:41:25 +10302327 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002328 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002329
2330 if (msg == NULL || payload_length == NULL) {
2331 return -EINVAL;
2332 }
2333
2334 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2335 PLDM_TRANSFER_COMPLETE, msg);
2336 if (rc) {
2337 return -EINVAL;
2338 }
2339
2340 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2341 if (rc) {
2342 return rc;
2343 }
2344
Andrew Jefferya1896962025-03-03 21:41:25 +10302345 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002346
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302347 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002348}
2349
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302350LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302351int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2352 struct pldm_msg *msg, size_t payload_length)
2353{
2354 if (msg == NULL) {
2355 return PLDM_ERROR_INVALID_DATA;
2356 }
2357
2358 if (payload_length != sizeof(completion_code)) {
2359 return PLDM_ERROR_INVALID_LENGTH;
2360 }
2361
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302362 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302363 header.instance = instance_id;
2364 header.msg_type = PLDM_RESPONSE;
2365 header.pldm_type = PLDM_FWUP;
2366 header.command = PLDM_TRANSFER_COMPLETE;
2367 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2368 if (rc) {
2369 return rc;
2370 }
2371
2372 msg->payload[0] = completion_code;
2373
2374 return PLDM_SUCCESS;
2375}
2376
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302377LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302378int decode_verify_complete_req(const struct pldm_msg *msg,
2379 size_t payload_length, uint8_t *verify_result)
2380{
2381 if (msg == NULL || verify_result == NULL) {
2382 return PLDM_ERROR_INVALID_DATA;
2383 }
2384
2385 if (payload_length != sizeof(*verify_result)) {
2386 return PLDM_ERROR_INVALID_LENGTH;
2387 }
2388
2389 *verify_result = msg->payload[0];
2390 return PLDM_SUCCESS;
2391}
2392
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002393LIBPLDM_ABI_TESTING
2394int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2395 struct pldm_msg *msg, size_t *payload_length)
2396{
Andrew Jefferya1896962025-03-03 21:41:25 +10302397 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002398 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002399
2400 if (msg == NULL || payload_length == NULL) {
2401 return -EINVAL;
2402 }
2403
2404 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2405 PLDM_VERIFY_COMPLETE, msg);
2406 if (rc) {
2407 return EINVAL;
2408 }
2409
2410 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2411 if (rc) {
2412 return rc;
2413 }
2414
Andrew Jefferya1896962025-03-03 21:41:25 +10302415 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002416
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302417 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002418}
2419
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302420LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302421int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2422 struct pldm_msg *msg, size_t payload_length)
2423{
2424 if (msg == NULL) {
2425 return PLDM_ERROR_INVALID_DATA;
2426 }
2427
2428 if (payload_length != sizeof(completion_code)) {
2429 return PLDM_ERROR_INVALID_LENGTH;
2430 }
2431
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302432 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302433 header.instance = instance_id;
2434 header.msg_type = PLDM_RESPONSE;
2435 header.pldm_type = PLDM_FWUP;
2436 header.command = PLDM_VERIFY_COMPLETE;
2437 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2438 if (rc) {
2439 return rc;
2440 }
2441
2442 msg->payload[0] = completion_code;
2443
2444 return PLDM_SUCCESS;
2445}
2446
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302447LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302448int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2449 uint8_t *apply_result,
2450 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302451{
2452 if (msg == NULL || apply_result == NULL ||
2453 comp_activation_methods_modification == NULL) {
2454 return PLDM_ERROR_INVALID_DATA;
2455 }
2456
2457 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2458 return PLDM_ERROR_INVALID_LENGTH;
2459 }
2460
2461 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302462 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302463
2464 *apply_result = request->apply_result;
2465 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302466 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302467
2468 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2469 comp_activation_methods_modification->value) {
2470 return PLDM_ERROR_INVALID_DATA;
2471 }
2472
2473 return PLDM_SUCCESS;
2474}
2475
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002476LIBPLDM_ABI_TESTING
2477int encode_apply_complete_req(uint8_t instance_id,
2478 const struct pldm_apply_complete_req *req_data,
2479 struct pldm_msg *msg, size_t *payload_length)
2480{
Andrew Jefferya1896962025-03-03 21:41:25 +10302481 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002482 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002483
2484 if (msg == NULL || payload_length == NULL) {
2485 return -EINVAL;
2486 }
2487
2488 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2489 PLDM_APPLY_COMPLETE, msg);
2490 if (rc) {
2491 return -EINVAL;
2492 }
2493
2494 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2495 if (rc) {
2496 return rc;
2497 }
2498
2499 pldm_msgbuf_insert(buf, req_data->apply_result);
2500 pldm_msgbuf_insert(
2501 buf, req_data->comp_activation_methods_modification.value);
2502
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302503 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002504}
2505
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302506LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302507int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2508 struct pldm_msg *msg, size_t payload_length)
2509{
2510 if (msg == NULL) {
2511 return PLDM_ERROR_INVALID_DATA;
2512 }
2513
2514 if (payload_length != sizeof(completion_code)) {
2515 return PLDM_ERROR_INVALID_LENGTH;
2516 }
2517
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302518 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302519 header.instance = instance_id;
2520 header.msg_type = PLDM_RESPONSE;
2521 header.pldm_type = PLDM_FWUP;
2522 header.command = PLDM_APPLY_COMPLETE;
2523 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2524 if (rc) {
2525 return rc;
2526 }
2527
2528 msg->payload[0] = completion_code;
2529
2530 return PLDM_SUCCESS;
2531}
2532
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002533LIBPLDM_ABI_TESTING
2534int decode_activate_firmware_req(const struct pldm_msg *msg,
2535 size_t payload_length, bool *self_contained)
2536{
Andrew Jefferya1896962025-03-03 21:41:25 +10302537 uint8_t self_contained_u8 = 0;
2538 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002539 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002540
2541 if (msg == NULL || self_contained == NULL) {
2542 return -EINVAL;
2543 }
2544
2545 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2546 if (rc) {
2547 return 0;
2548 }
2549
Andrew Jefferya1896962025-03-03 21:41:25 +10302550 pldm_msgbuf_extract(buf, self_contained_u8);
2551
2552 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002553 if (rc) {
2554 return rc;
2555 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302556
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002557 *self_contained = (bool)self_contained_u8;
2558 return 0;
2559}
2560
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302561LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302562int encode_activate_firmware_req(uint8_t instance_id,
2563 bool8_t self_contained_activation_req,
2564 struct pldm_msg *msg, size_t payload_length)
2565{
2566 if (msg == NULL) {
2567 return PLDM_ERROR_INVALID_DATA;
2568 }
2569
2570 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2571 return PLDM_ERROR_INVALID_LENGTH;
2572 }
2573
2574 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302575 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302576 return PLDM_ERROR_INVALID_DATA;
2577 }
2578
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302579 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302580 header.instance = instance_id;
2581 header.msg_type = PLDM_REQUEST;
2582 header.pldm_type = PLDM_FWUP;
2583 header.command = PLDM_ACTIVATE_FIRMWARE;
2584 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2585 if (rc) {
2586 return rc;
2587 }
2588
2589 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302590 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302591
2592 request->self_contained_activation_req = self_contained_activation_req;
2593
2594 return PLDM_SUCCESS;
2595}
2596
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302597LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302598int decode_activate_firmware_resp(const struct pldm_msg *msg,
2599 size_t payload_length,
2600 uint8_t *completion_code,
2601 uint16_t *estimated_time_activation)
2602{
2603 if (msg == NULL || completion_code == NULL ||
2604 estimated_time_activation == NULL || !payload_length) {
2605 return PLDM_ERROR_INVALID_DATA;
2606 }
2607
2608 *completion_code = msg->payload[0];
2609 if (*completion_code != PLDM_SUCCESS) {
2610 return PLDM_SUCCESS;
2611 }
2612
2613 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2614 return PLDM_ERROR_INVALID_LENGTH;
2615 }
2616
2617 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302618 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302619
2620 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302621 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302622
2623 return PLDM_SUCCESS;
2624}
2625
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002626LIBPLDM_ABI_TESTING
2627int encode_activate_firmware_resp(
2628 uint8_t instance_id,
2629 const struct pldm_activate_firmware_resp *resp_data,
2630 struct pldm_msg *msg, size_t *payload_length)
2631{
Andrew Jefferya1896962025-03-03 21:41:25 +10302632 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002633 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002634
2635 if (msg == NULL || payload_length == NULL) {
2636 return -EINVAL;
2637 }
2638
2639 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2640 PLDM_ACTIVATE_FIRMWARE, msg);
2641 if (rc) {
2642 return -EINVAL;
2643 }
2644
2645 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2646 if (rc) {
2647 return rc;
2648 }
2649
2650 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2651 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2652
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302653 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002654}
2655
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302656LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302657int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2658 size_t payload_length)
2659{
2660 if (msg == NULL) {
2661 return PLDM_ERROR_INVALID_DATA;
2662 }
2663
2664 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2665 return PLDM_ERROR_INVALID_LENGTH;
2666 }
2667
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302668 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302669 header.instance = instance_id;
2670 header.msg_type = PLDM_REQUEST;
2671 header.pldm_type = PLDM_FWUP;
2672 header.command = PLDM_GET_STATUS;
2673 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2674 if (rc) {
2675 return rc;
2676 }
2677
2678 return PLDM_SUCCESS;
2679}
2680
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302681LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302682int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2683 uint8_t *completion_code, uint8_t *current_state,
2684 uint8_t *previous_state, uint8_t *aux_state,
2685 uint8_t *aux_state_status, uint8_t *progress_percent,
2686 uint8_t *reason_code,
2687 bitfield32_t *update_option_flags_enabled)
2688{
2689 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2690 previous_state == NULL || aux_state == NULL ||
2691 aux_state_status == NULL || progress_percent == NULL ||
2692 reason_code == NULL || update_option_flags_enabled == NULL ||
2693 !payload_length) {
2694 return PLDM_ERROR_INVALID_DATA;
2695 }
2696
2697 *completion_code = msg->payload[0];
2698 if (*completion_code != PLDM_SUCCESS) {
2699 return PLDM_SUCCESS;
2700 }
2701
2702 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2703 return PLDM_ERROR_INVALID_LENGTH;
2704 }
2705 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302706 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302707
2708 if (!is_state_valid(response->current_state)) {
2709 return PLDM_ERROR_INVALID_DATA;
2710 }
2711 if (!is_state_valid(response->previous_state)) {
2712 return PLDM_ERROR_INVALID_DATA;
2713 }
2714 if (!is_aux_state_valid(response->aux_state)) {
2715 return PLDM_ERROR_INVALID_DATA;
2716 }
2717 if (!is_aux_state_status_valid(response->aux_state_status)) {
2718 return PLDM_ERROR_INVALID_DATA;
2719 }
2720 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2721 return PLDM_ERROR_INVALID_DATA;
2722 }
2723 if (!is_reason_code_valid(response->reason_code)) {
2724 return PLDM_ERROR_INVALID_DATA;
2725 }
2726
2727 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2728 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2729 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2730 if (response->aux_state !=
2731 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2732 return PLDM_ERROR_INVALID_DATA;
2733 }
2734 }
2735
2736 *current_state = response->current_state;
2737 *previous_state = response->previous_state;
2738 *aux_state = response->aux_state;
2739 *aux_state_status = response->aux_state_status;
2740 *progress_percent = response->progress_percent;
2741 *reason_code = response->reason_code;
2742 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302743 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302744
2745 return PLDM_SUCCESS;
2746}
2747
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002748LIBPLDM_ABI_TESTING
2749int encode_get_status_resp(uint8_t instance_id,
2750 const struct pldm_get_status_resp *status,
2751 struct pldm_msg *msg, size_t *payload_length)
2752{
Andrew Jefferya1896962025-03-03 21:41:25 +10302753 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002754 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002755
2756 if (status == NULL || msg == NULL || payload_length == NULL) {
2757 return -EINVAL;
2758 }
2759
2760 if (status->completion_code != PLDM_SUCCESS) {
2761 return -EINVAL;
2762 }
2763
2764 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2765 PLDM_GET_STATUS, msg);
2766 if (rc) {
2767 return -EINVAL;
2768 }
2769
2770 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2771 if (rc) {
2772 return rc;
2773 }
2774
2775 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2776 pldm_msgbuf_insert(buf, status->current_state);
2777 pldm_msgbuf_insert(buf, status->previous_state);
2778 pldm_msgbuf_insert(buf, status->aux_state);
2779 pldm_msgbuf_insert(buf, status->aux_state_status);
2780 pldm_msgbuf_insert(buf, status->progress_percent);
2781 pldm_msgbuf_insert(buf, status->reason_code);
2782 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
2783
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302784 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002785}
2786
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302787LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302788int encode_cancel_update_component_req(uint8_t instance_id,
2789 struct pldm_msg *msg,
2790 size_t payload_length)
2791{
2792 if (msg == NULL) {
2793 return PLDM_ERROR_INVALID_DATA;
2794 }
2795
2796 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
2797 return PLDM_ERROR_INVALID_LENGTH;
2798 }
2799
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302800 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302801 header.instance = instance_id;
2802 header.msg_type = PLDM_REQUEST;
2803 header.pldm_type = PLDM_FWUP;
2804 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
2805 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2806 if (rc) {
2807 return rc;
2808 }
2809
2810 return PLDM_SUCCESS;
2811}
2812
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302813LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302814int decode_cancel_update_component_resp(const struct pldm_msg *msg,
2815 size_t payload_length,
2816 uint8_t *completion_code)
2817{
2818 if (msg == NULL || completion_code == NULL) {
2819 return PLDM_ERROR_INVALID_DATA;
2820 }
2821
2822 if (payload_length != sizeof(*completion_code)) {
2823 return PLDM_ERROR_INVALID_LENGTH;
2824 }
2825
2826 *completion_code = msg->payload[0];
2827 return PLDM_SUCCESS;
2828}
2829
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302830LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302831int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
2832 size_t payload_length)
2833{
2834 if (msg == NULL) {
2835 return PLDM_ERROR_INVALID_DATA;
2836 }
2837
2838 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
2839 return PLDM_ERROR_INVALID_LENGTH;
2840 }
2841
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302842 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302843 header.instance = instance_id;
2844 header.msg_type = PLDM_REQUEST;
2845 header.pldm_type = PLDM_FWUP;
2846 header.command = PLDM_CANCEL_UPDATE;
2847 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2848 if (rc) {
2849 return rc;
2850 }
2851
2852 return PLDM_SUCCESS;
2853}
2854
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302855LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302856int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
2857 uint8_t *completion_code,
2858 bool8_t *non_functioning_component_indication,
2859 bitfield64_t *non_functioning_component_bitmap)
2860{
2861 if (msg == NULL || completion_code == NULL ||
2862 non_functioning_component_indication == NULL ||
2863 non_functioning_component_bitmap == NULL || !payload_length) {
2864 return PLDM_ERROR_INVALID_DATA;
2865 }
2866
2867 *completion_code = msg->payload[0];
2868 if (*completion_code != PLDM_SUCCESS) {
2869 return PLDM_SUCCESS;
2870 }
2871
2872 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
2873 return PLDM_ERROR_INVALID_LENGTH;
2874 }
2875 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302876 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302877
2878 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302879 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302880 return PLDM_ERROR_INVALID_DATA;
2881 }
2882
2883 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302884 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302885
2886 if (*non_functioning_component_indication) {
2887 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302888 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302889 }
2890
2891 return PLDM_SUCCESS;
2892}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002893
2894LIBPLDM_ABI_TESTING
2895int encode_cancel_update_resp(uint8_t instance_id,
2896 const struct pldm_cancel_update_resp *resp_data,
2897 struct pldm_msg *msg, size_t *payload_length)
2898{
Andrew Jefferya1896962025-03-03 21:41:25 +10302899 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002900 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002901
2902 if (msg == NULL || payload_length == NULL) {
2903 return -EINVAL;
2904 }
2905
2906 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2907 PLDM_CANCEL_UPDATE, msg);
2908 if (rc) {
2909 return -EINVAL;
2910 }
2911
2912 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2913 if (rc) {
2914 return rc;
2915 }
2916
2917 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2918 pldm_msgbuf_insert(buf,
2919 resp_data->non_functioning_component_indication);
2920 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
2921
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302922 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002923}