blob: 534d0684f02b8f865e29ee23084c13939b964b7d [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 Jeffery37dd6a32023-05-12 16:04:06 +0930330 const uint8_t *data, size_t length,
331 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 Jeffery37dd6a32023-05-12 16:04:06 +0930377 data + sizeof(struct pldm_package_header_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378 package_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930379 package_header_info->package_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030381 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930382}
383
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930384LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030385int decode_pldm_package_header_info(
386 const uint8_t *data, size_t length,
387 struct pldm_package_header_information *package_header_info,
388 struct variable_field *package_version_str)
389{
390 int rc;
391
392 rc = decode_pldm_package_header_info_errno(
393 data, length, package_header_info, package_version_str);
394 if (rc < 0) {
395 return pldm_xlate_errno(rc);
396 }
397
398 return PLDM_SUCCESS;
399}
400
401static int decode_firmware_device_id_record_errno(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930402 const uint8_t *data, size_t length,
403 uint16_t component_bitmap_bit_length,
404 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 Jeffery37dd6a32023-05-12 16:04:06 +0930466 data + sizeof(struct pldm_firmware_device_id_record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930467 applicable_components->length = applicable_components_length;
468
469 comp_image_set_version_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930470 applicable_components->ptr + applicable_components->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471 comp_image_set_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930472 fw_device_id_record->comp_image_set_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930473
474 record_descriptors->ptr = comp_image_set_version_str->ptr +
475 comp_image_set_version_str->length;
476 record_descriptors->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930477 fw_device_id_record->record_length -
478 sizeof(struct pldm_firmware_device_id_record) -
479 applicable_components_length -
480 fw_device_id_record->comp_image_set_version_string_length -
481 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930482
483 if (fw_device_id_record->fw_device_pkg_data_length) {
484 fw_device_pkg_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930485 record_descriptors->ptr + record_descriptors->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930486 fw_device_pkg_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930487 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930488 }
489
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030490 return 0;
491}
492
493LIBPLDM_ABI_STABLE
494int decode_firmware_device_id_record(
495 const uint8_t *data, size_t length,
496 uint16_t component_bitmap_bit_length,
497 struct pldm_firmware_device_id_record *fw_device_id_record,
498 struct variable_field *applicable_components,
499 struct variable_field *comp_image_set_version_str,
500 struct variable_field *record_descriptors,
501 struct variable_field *fw_device_pkg_data)
502{
503 int rc;
504
505 rc = decode_firmware_device_id_record_errno(
506 data, length, component_bitmap_bit_length, fw_device_id_record,
507 applicable_components, comp_image_set_version_str,
508 record_descriptors, fw_device_pkg_data);
509 if (rc < 0) {
510 return pldm_xlate_errno(rc);
511 }
512
Andrew Jeffery9c766792022-08-10 23:12:49 +0930513 return PLDM_SUCCESS;
514}
515
Unive Tiene5c3f142024-12-13 14:14:19 +0800516LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030517int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
518 struct pldm_descriptor *desc)
519{
520 struct pldm_msgbuf _buf;
521 struct pldm_msgbuf *buf = &_buf;
522 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) {
537 return rc;
538 }
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
547 return pldm_msgbuf_destroy(buf);
548}
549
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030550static int decode_descriptor_type_length_value_errno(
551 const uint8_t *data, size_t length, uint16_t *descriptor_type,
552 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 Jeffery37dd6a32023-05-12 16:04:06 +0930605 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
606 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 Jeffery37dd6a32023-05-12 16:04:06 +0930668 const uint8_t *data, size_t length,
669 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
723 comp_version_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930724 data + 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{
819 int rc;
820 struct pldm_msgbuf _buf;
821 struct pldm_msgbuf *buf = &_buf;
822
823 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
824 return -EINVAL;
825 }
826
827 if (descriptor_count < 1) {
828 return -EINVAL;
829 }
830
831 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
832 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
833 if (rc) {
834 return -EINVAL;
835 }
836
837 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
838 if (rc) {
839 return rc;
840 }
841
842 /* Determine total length */
843 uint32_t device_identifiers_len = 0;
844 for (uint8_t i = 0; i < descriptor_count; i++) {
845 const struct pldm_descriptor *d = &descriptors[i];
846 device_identifiers_len +=
847 2 * sizeof(uint16_t) + d->descriptor_length;
848 }
849
850 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
851 pldm_msgbuf_insert(buf, device_identifiers_len);
852 pldm_msgbuf_insert(buf, descriptor_count);
853
854 for (uint8_t i = 0; i < descriptor_count; i++) {
855 const struct pldm_descriptor *d = &descriptors[i];
856 pldm_msgbuf_insert(buf, d->descriptor_type);
857 pldm_msgbuf_insert(buf, d->descriptor_length);
858 if (d->descriptor_data == NULL) {
859 return -EINVAL;
860 }
861 rc = pldm_msgbuf_insert_array(
862 buf, d->descriptor_length,
863 (const uint8_t *)d->descriptor_data,
864 d->descriptor_length);
865 if (rc) {
866 return rc;
867 }
868 }
869
870 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
871}
872
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930873LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930874int encode_get_firmware_parameters_req(uint8_t instance_id,
875 size_t payload_length,
876 struct pldm_msg *msg)
877{
878 if (msg == NULL) {
879 return PLDM_ERROR_INVALID_DATA;
880 }
881
882 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
883 return PLDM_ERROR_INVALID_LENGTH;
884 }
885
886 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
887 PLDM_GET_FIRMWARE_PARAMETERS, msg);
888}
889
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930890LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930892 const struct pldm_msg *msg, size_t payload_length,
893 struct pldm_get_firmware_parameters_resp *resp_data,
894 struct variable_field *active_comp_image_set_ver_str,
895 struct variable_field *pending_comp_image_set_ver_str,
896 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930897{
898 if (msg == NULL || resp_data == NULL ||
899 active_comp_image_set_ver_str == NULL ||
900 pending_comp_image_set_ver_str == NULL ||
901 comp_parameter_table == NULL || !payload_length) {
902 return PLDM_ERROR_INVALID_DATA;
903 }
904
905 resp_data->completion_code = msg->payload[0];
906 if (PLDM_SUCCESS != resp_data->completion_code) {
907 return PLDM_SUCCESS;
908 }
909
910 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
911 return PLDM_ERROR_INVALID_LENGTH;
912 }
913
914 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930915 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916
917 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930918 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919 (response->active_comp_image_set_ver_str_len == 0)) {
920 return PLDM_ERROR_INVALID_DATA;
921 }
922
923 if (response->pending_comp_image_set_ver_str_len == 0) {
924 if (response->pending_comp_image_set_ver_str_type !=
925 PLDM_STR_TYPE_UNKNOWN) {
926 return PLDM_ERROR_INVALID_DATA;
927 }
928 } else {
929 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930930 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931 return PLDM_ERROR_INVALID_DATA;
932 }
933 }
934
935 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930936 sizeof(struct pldm_get_firmware_parameters_resp) +
937 response->active_comp_image_set_ver_str_len +
938 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930939
940 if (payload_length < partial_response_length) {
941 return PLDM_ERROR_INVALID_LENGTH;
942 }
943
944 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930945 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946 resp_data->comp_count = le16toh(response->comp_count);
947 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930948 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930950 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930952 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930954 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955
956 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930957 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930959 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960
961 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
962 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930963 msg->payload +
964 sizeof(struct pldm_get_firmware_parameters_resp) +
965 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930966 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930967 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930968 } else {
969 pending_comp_image_set_ver_str->ptr = NULL;
970 pending_comp_image_set_ver_str->length = 0;
971 }
972
973 if (payload_length > partial_response_length && resp_data->comp_count) {
974 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930975 msg->payload +
976 sizeof(struct pldm_get_firmware_parameters_resp) +
977 resp_data->active_comp_image_set_ver_str_len +
978 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930980 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981 } else {
982 comp_parameter_table->ptr = NULL;
983 comp_parameter_table->length = 0;
984 }
985
986 return PLDM_SUCCESS;
987}
988
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800989LIBPLDM_ABI_TESTING
990int encode_get_firmware_parameters_resp(
991 uint8_t instance_id,
992 const struct pldm_get_firmware_parameters_resp_full *resp_data,
993 struct pldm_msg *msg, size_t *payload_length)
994{
995 int rc;
996 struct pldm_msgbuf _buf;
997 struct pldm_msgbuf *buf = &_buf;
998
999 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1000 return -EINVAL;
1001 }
1002
1003 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1004 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1005 if (rc) {
1006 return -EINVAL;
1007 }
1008
1009 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1010 if (rc) {
1011 return rc;
1012 }
1013
1014 pldm_msgbuf_insert(buf, resp_data->completion_code);
1015 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1016 pldm_msgbuf_insert(buf, resp_data->comp_count);
1017 pldm_msgbuf_insert(buf,
1018 resp_data->active_comp_image_set_ver_str.str_type);
1019 pldm_msgbuf_insert(buf,
1020 resp_data->active_comp_image_set_ver_str.str_len);
1021 pldm_msgbuf_insert(buf,
1022 resp_data->pending_comp_image_set_ver_str.str_type);
1023 pldm_msgbuf_insert(buf,
1024 resp_data->pending_comp_image_set_ver_str.str_len);
1025 /* String data appended */
1026 rc = pldm_msgbuf_insert_array(
1027 buf, resp_data->active_comp_image_set_ver_str.str_len,
1028 resp_data->active_comp_image_set_ver_str.str_data,
1029 resp_data->active_comp_image_set_ver_str.str_len);
1030 if (rc) {
1031 return rc;
1032 }
1033 rc = pldm_msgbuf_insert_array(
1034 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1035 resp_data->pending_comp_image_set_ver_str.str_data,
1036 resp_data->pending_comp_image_set_ver_str.str_len);
1037 if (rc) {
1038 return rc;
1039 }
1040
1041 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1042 * will populate the remainder */
1043
1044 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
1045}
1046
1047LIBPLDM_ABI_TESTING
1048int encode_get_firmware_parameters_resp_comp_entry(
1049 const struct pldm_component_parameter_entry_full *comp,
1050 uint8_t *payload, size_t *payload_length)
1051{
1052 int rc;
1053 struct pldm_msgbuf _buf;
1054 struct pldm_msgbuf *buf = &_buf;
1055
1056 if (comp == NULL || payload == NULL || payload_length == NULL) {
1057 return -EINVAL;
1058 }
1059
1060 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1061 if (rc) {
1062 return rc;
1063 }
1064
1065 pldm_msgbuf_insert(buf, comp->comp_classification);
1066 pldm_msgbuf_insert(buf, comp->comp_identifier);
1067 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1068
1069 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1070 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1071 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1072 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1073 comp->active_ver.date,
1074 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1075 if (rc) {
1076 return rc;
1077 }
1078
1079 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1080 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1081 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1082 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1083 comp->pending_ver.date,
1084 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1085 if (rc) {
1086 return rc;
1087 }
1088
1089 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1090 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1091
1092 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1093 comp->active_ver.str.str_data,
1094 comp->active_ver.str.str_len);
1095 if (rc) {
1096 return rc;
1097 }
1098 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1099 comp->pending_ver.str.str_data,
1100 comp->pending_ver.str.str_len);
1101 if (rc) {
1102 return rc;
1103 }
1104
1105 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
1106}
1107
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301108LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301109int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301110 const uint8_t *data, size_t length,
1111 struct pldm_component_parameter_entry *component_data,
1112 struct variable_field *active_comp_ver_str,
1113 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301114{
1115 if (data == NULL || component_data == NULL ||
1116 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1117 return PLDM_ERROR_INVALID_DATA;
1118 }
1119
1120 if (length < sizeof(struct pldm_component_parameter_entry)) {
1121 return PLDM_ERROR_INVALID_LENGTH;
1122 }
1123
1124 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301125 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301126
1127 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1128 entry->active_comp_ver_str_len +
1129 entry->pending_comp_ver_str_len;
1130
1131 if (length < entry_length) {
1132 return PLDM_ERROR_INVALID_LENGTH;
1133 }
1134
1135 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301136 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 component_data->comp_identifier = le16toh(entry->comp_identifier);
1138 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301139 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301140 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301141 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301142 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301143 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301144 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301145 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146 memcpy(component_data->active_comp_release_date,
1147 entry->active_comp_release_date,
1148 sizeof(entry->active_comp_release_date));
1149 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301150 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301151 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301152 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301153 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301154 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301155 memcpy(component_data->pending_comp_release_date,
1156 entry->pending_comp_release_date,
1157 sizeof(entry->pending_comp_release_date));
1158 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301159 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301160 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301161 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301162
1163 if (entry->active_comp_ver_str_len != 0) {
1164 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301165 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1167 } else {
1168 active_comp_ver_str->ptr = NULL;
1169 active_comp_ver_str->length = 0;
1170 }
1171
1172 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301173 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301174 data + sizeof(struct pldm_component_parameter_entry) +
1175 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301176 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1177 } else {
1178 pending_comp_ver_str->ptr = NULL;
1179 pending_comp_ver_str->length = 0;
1180 }
1181 return PLDM_SUCCESS;
1182}
1183
Unive Tiene5c3f142024-12-13 14:14:19 +08001184LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001185int encode_query_downstream_devices_req(uint8_t instance_id,
1186 struct pldm_msg *msg)
1187{
1188 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001189 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001190 }
1191
Unive Tien71e935c2024-11-25 17:21:43 +08001192 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1193 PLDM_FWUP,
1194 PLDM_QUERY_DOWNSTREAM_DEVICES,
1195 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001196}
1197
Unive Tiene5c3f142024-12-13 14:14:19 +08001198LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001199int decode_query_downstream_devices_resp(
1200 const struct pldm_msg *msg, size_t payload_length,
1201 struct pldm_query_downstream_devices_resp *resp_data)
1202{
1203 struct pldm_msgbuf _buf;
1204 struct pldm_msgbuf *buf = &_buf;
1205 int rc;
1206
1207 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001208 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001209 }
1210
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301211 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1212 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001213 if (rc) {
1214 return rc;
1215 }
1216
1217 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1218 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001219 return rc;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001220 }
1221 if (PLDM_SUCCESS != resp_data->completion_code) {
1222 // Return the CC directly without decoding the rest of the payload
Unive Tien71e935c2024-11-25 17:21:43 +08001223 return 0;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001224 }
1225
1226 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Unive Tien71e935c2024-11-25 17:21:43 +08001227 return -EBADMSG;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001228 }
1229
1230 rc = pldm_msgbuf_extract(buf,
1231 resp_data->downstream_device_update_supported);
1232 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001233 return rc;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001234 }
1235
1236 if (!is_downstream_device_update_support_valid(
1237 resp_data->downstream_device_update_supported)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001238 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001239 }
1240
1241 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1242 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1243 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1244
Unive Tien71e935c2024-11-25 17:21:43 +08001245 return pldm_msgbuf_destroy_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001246}
1247
Unive Tiene5c3f142024-12-13 14:14:19 +08001248LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001249int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001250 uint8_t instance_id,
1251 const struct pldm_query_downstream_identifiers_req *params_req,
1252 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001253{
1254 struct pldm_msgbuf _buf;
1255 struct pldm_msgbuf *buf = &_buf;
1256 int rc;
1257
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001258 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001259 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001260 }
1261
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001262 if (!is_transfer_operation_flag_valid(
1263 (enum transfer_op_flag)
1264 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001265 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001266 }
1267
1268 struct pldm_header_info header = { 0 };
1269 header.instance = instance_id;
1270 header.msg_type = PLDM_REQUEST;
1271 header.pldm_type = PLDM_FWUP;
1272 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001273 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001274 if (rc) {
1275 return rc;
1276 }
1277
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301278 rc = pldm_msgbuf_init_errno(buf,
1279 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1280 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001281 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001282 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001283 }
1284
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001285 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001286 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001287 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001288
Unive Tien71e935c2024-11-25 17:21:43 +08001289 return pldm_msgbuf_destroy(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001290}
1291
Unive Tiene5c3f142024-12-13 14:14:19 +08001292LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001293int decode_query_downstream_identifiers_resp(
1294 const struct pldm_msg *msg, size_t payload_length,
1295 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301296 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001297{
1298 struct pldm_msgbuf _buf;
1299 struct pldm_msgbuf *buf = &_buf;
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301300 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001301 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001302
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301303 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001304 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001305 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001306 }
1307
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301308 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1309 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001310 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001311 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001312 }
1313
1314 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1315 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001316 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001317 }
1318 if (PLDM_SUCCESS != resp_data->completion_code) {
Unive Tien71e935c2024-11-25 17:21:43 +08001319 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001320 }
1321
1322 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Unive Tien71e935c2024-11-25 17:21:43 +08001323 return -EBADMSG;
Chris Wang458475a2024-03-26 17:59:19 +08001324 }
1325
1326 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1327 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1328
1329 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1330 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001331 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001332 }
1333
1334 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301335 rc = pldm_msgbuf_span_required(
1336 buf, resp_data->downstream_devices_length, &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001337 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001338 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001339 }
Chris Wang458475a2024-03-26 17:59:19 +08001340
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301341 rc = pldm_msgbuf_destroy(buf);
1342 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001343 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301344 }
1345
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301346 iter->field.ptr = remaining;
1347 iter->field.length = resp_data->downstream_devices_length;
1348 iter->devs = resp_data->number_of_downstream_devices;
1349
Unive Tien71e935c2024-11-25 17:21:43 +08001350 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001351}
1352
Unive Tiene5c3f142024-12-13 14:14:19 +08001353LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301354int decode_pldm_downstream_device_from_iter(
1355 struct pldm_downstream_device_iter *iter,
1356 struct pldm_downstream_device *dev)
1357{
1358 struct pldm_msgbuf _buf;
1359 struct pldm_msgbuf *buf = &_buf;
1360 int rc;
1361
1362 if (!iter || !dev) {
1363 return -EINVAL;
1364 }
1365
1366 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1367 iter->field.length);
1368 if (rc) {
1369 return rc;
1370 }
1371
1372 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1373 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
1374 iter->field.ptr = NULL;
1375 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1376 &iter->field.length);
1377
1378 return pldm_msgbuf_destroy(buf);
1379}
1380
Unive Tiene5c3f142024-12-13 14:14:19 +08001381LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301382int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001383 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301384 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001385 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001386{
1387 struct pldm_msgbuf _buf;
1388 struct pldm_msgbuf *buf = &_buf;
1389 int rc;
1390
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001391 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001392 return -EINVAL;
1393 }
1394
1395 rc = pldm_msgbuf_init_errno(
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301396 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
Chris Wangb6ef35b2024-07-03 09:35:42 +08001397 msg->payload, payload_length);
1398 if (rc < 0) {
1399 return rc;
1400 }
1401
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001402 if (!is_transfer_operation_flag_valid(
1403 (enum transfer_op_flag)
1404 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001405 return -EBADMSG;
1406 }
1407
1408 struct pldm_header_info header = { 0 };
1409 header.instance = instance_id;
1410 header.msg_type = PLDM_REQUEST;
1411 header.pldm_type = PLDM_FWUP;
1412 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1413 rc = pack_pldm_header_errno(&header, &msg->hdr);
1414 if (rc < 0) {
1415 return rc;
1416 }
1417
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001418 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001419 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001420 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001421
1422 return pldm_msgbuf_destroy(buf);
1423}
1424
Unive Tiene5c3f142024-12-13 14:14:19 +08001425LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301426int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001427 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301428 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301429 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001430{
1431 struct pldm_msgbuf _buf;
1432 struct pldm_msgbuf *buf = &_buf;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301433 void *remaining = NULL;
1434 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001435 int rc;
1436
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301437 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001438 return -EINVAL;
1439 }
1440
1441 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1442 msg->payload, payload_length);
1443 if (rc < 0) {
1444 return rc;
1445 }
1446
1447 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1448 if (rc < 0) {
1449 return rc;
1450 }
1451 if (PLDM_SUCCESS != resp_data->completion_code) {
1452 return 0;
1453 }
1454
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301455 if (payload_length <
1456 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001457 return -EBADMSG;
1458 }
1459
1460 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1461 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1462 pldm_msgbuf_extract(buf,
1463 resp_data->fdp_capabilities_during_update.value);
1464 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1465
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301466 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1467 if (rc) {
1468 return rc;
1469 }
1470
1471 rc = pldm_msgbuf_destroy(buf);
1472 if (rc) {
1473 return rc;
1474 }
1475
1476 iter->field.ptr = remaining;
1477 iter->field.length = length;
1478 iter->entries = resp_data->downstream_device_count;
1479
1480 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001481}
1482
Unive Tiene5c3f142024-12-13 14:14:19 +08001483LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301484int decode_pldm_downstream_device_parameters_entry_from_iter(
1485 struct pldm_downstream_device_parameters_iter *iter,
1486 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001487{
1488 struct pldm_msgbuf _buf;
1489 struct pldm_msgbuf *buf = &_buf;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301490 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001491 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301492 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001493 int rc;
1494
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301495 if (iter == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001496 return -EINVAL;
1497 }
1498
1499 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301500 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1501 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001502 if (rc < 0) {
1503 return rc;
1504 }
1505
1506 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1507 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1508 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1509 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1510 if (rc < 0) {
1511 return rc;
1512 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001513 rc = pldm_msgbuf_extract_array(buf,
1514 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1515 entry->active_comp_release_date,
1516 sizeof(entry->active_comp_release_date));
1517 if (rc < 0) {
1518 return rc;
1519 }
1520
Chris Wangb6ef35b2024-07-03 09:35:42 +08001521 // Fill the last byte with NULL character
1522 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1523 '\0';
1524
1525 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1526 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1527 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1528 if (rc < 0) {
1529 return rc;
1530 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001531
1532 rc = pldm_msgbuf_extract_array(
1533 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1534 entry->pending_comp_release_date,
1535 sizeof(entry->pending_comp_release_date));
1536 if (rc < 0) {
1537 return rc;
1538 }
1539
Chris Wangb6ef35b2024-07-03 09:35:42 +08001540 // Fill the last byte with NULL character
1541 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1542 '\0';
1543
1544 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1545 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001546
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301547 comp_ver_str = NULL;
1548 pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1549 &comp_ver_str);
1550 entry->active_comp_ver_str = comp_ver_str;
1551
1552 comp_ver_str = NULL;
1553 pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1554 &comp_ver_str);
1555 entry->pending_comp_ver_str = comp_ver_str;
1556
1557 cursor = NULL;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001558 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1559 if (rc < 0) {
1560 return rc;
1561 }
1562
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301563 iter->field.ptr = cursor;
1564 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001565
1566 return 0;
1567}
1568
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301569LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301570int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1571 uint16_t num_of_comp,
1572 uint8_t max_outstanding_transfer_req,
1573 uint16_t pkg_data_len,
1574 uint8_t comp_image_set_ver_str_type,
1575 uint8_t comp_image_set_ver_str_len,
1576 const struct variable_field *comp_img_set_ver_str,
1577 struct pldm_msg *msg, size_t payload_length)
1578{
1579 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1580 msg == NULL) {
1581 return PLDM_ERROR_INVALID_DATA;
1582 }
1583
1584 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301585 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301586 return PLDM_ERROR_INVALID_LENGTH;
1587 }
1588
1589 if ((comp_image_set_ver_str_len == 0) ||
1590 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1591 return PLDM_ERROR_INVALID_DATA;
1592 }
1593
1594 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1595 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1596 return PLDM_ERROR_INVALID_DATA;
1597 }
1598
1599 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1600 return PLDM_ERROR_INVALID_DATA;
1601 }
1602
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301603 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301604 header.instance = instance_id;
1605 header.msg_type = PLDM_REQUEST;
1606 header.pldm_type = PLDM_FWUP;
1607 header.command = PLDM_REQUEST_UPDATE;
1608 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1609 if (rc) {
1610 return rc;
1611 }
1612
1613 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301614 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301615
1616 request->max_transfer_size = htole32(max_transfer_size);
1617 request->num_of_comp = htole16(num_of_comp);
1618 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1619 request->pkg_data_len = htole16(pkg_data_len);
1620 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1621 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1622
1623 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1624 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1625
1626 return PLDM_SUCCESS;
1627}
1628
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001629LIBPLDM_ABI_TESTING
1630int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1631 struct pldm_request_update_req_full *req)
1632{
1633 int rc;
1634 uint8_t t;
1635 struct pldm_msgbuf _buf;
1636 struct pldm_msgbuf *buf = &_buf;
1637
1638 if (msg == NULL || req == NULL) {
1639 return -EINVAL;
1640 }
1641
1642 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1643 if (rc) {
1644 return rc;
1645 }
1646
1647 pldm_msgbuf_extract(buf, req->max_transfer_size);
1648 pldm_msgbuf_extract(buf, req->num_of_comp);
1649 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
1650 pldm_msgbuf_extract(buf, req->pkg_data_len);
1651 rc = pldm_msgbuf_extract(buf, t);
1652 if (rc) {
1653 return rc;
1654 }
1655 if (t > PLDM_STR_TYPE_UTF_16BE) {
1656 return -EBADMSG;
1657 }
1658 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
1659 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
1660 if (rc) {
1661 return rc;
1662 }
1663
1664 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
1665 req->image_set_ver.str_data,
1666 PLDM_FIRMWARE_MAX_STRING);
1667 if (rc) {
1668 return rc;
1669 }
1670
1671 return pldm_msgbuf_destroy_consumed(buf);
1672}
1673
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301674LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301675int decode_request_update_resp(const struct pldm_msg *msg,
1676 size_t payload_length, uint8_t *completion_code,
1677 uint16_t *fd_meta_data_len,
1678 uint8_t *fd_will_send_pkg_data)
1679{
1680 if (msg == NULL || completion_code == NULL ||
1681 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
1682 !payload_length) {
1683 return PLDM_ERROR_INVALID_DATA;
1684 }
1685
1686 *completion_code = msg->payload[0];
1687 if (*completion_code != PLDM_SUCCESS) {
1688 return PLDM_SUCCESS;
1689 }
1690
1691 if (payload_length != sizeof(struct pldm_request_update_resp)) {
1692 return PLDM_ERROR_INVALID_LENGTH;
1693 }
1694
1695 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301696 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301697
1698 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
1699 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
1700
1701 return PLDM_SUCCESS;
1702}
1703
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001704LIBPLDM_ABI_TESTING
1705int encode_request_update_resp(uint8_t instance_id,
1706 const struct pldm_request_update_resp *resp_data,
1707 struct pldm_msg *msg, size_t *payload_length)
1708{
1709 int rc;
1710 struct pldm_msgbuf _buf;
1711 struct pldm_msgbuf *buf = &_buf;
1712
1713 if (msg == NULL || payload_length == NULL) {
1714 return -EINVAL;
1715 }
1716
1717 struct pldm_header_info header = {
1718 .instance = instance_id,
1719 .msg_type = PLDM_RESPONSE,
1720 .pldm_type = PLDM_FWUP,
1721 .command = PLDM_REQUEST_UPDATE,
1722 };
1723 rc = pack_pldm_header(&header, &(msg->hdr));
1724 if (rc) {
1725 return -EINVAL;
1726 }
1727
1728 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1729 if (rc) {
1730 return rc;
1731 }
1732
1733 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1734 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
1735 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
1736
1737 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
1738
1739 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
1740}
1741
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301742LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301743int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
1744 uint16_t comp_classification,
1745 uint16_t comp_identifier,
1746 uint8_t comp_classification_index,
1747 uint32_t comp_comparison_stamp,
1748 uint8_t comp_ver_str_type,
1749 uint8_t comp_ver_str_len,
1750 const struct variable_field *comp_ver_str,
1751 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301752{
1753 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1754 return PLDM_ERROR_INVALID_DATA;
1755 }
1756
1757 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301758 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301759 return PLDM_ERROR_INVALID_LENGTH;
1760 }
1761
1762 if ((comp_ver_str_len == 0) ||
1763 (comp_ver_str_len != comp_ver_str->length)) {
1764 return PLDM_ERROR_INVALID_DATA;
1765 }
1766
1767 if (!is_transfer_flag_valid(transfer_flag)) {
1768 return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
1769 }
1770
1771 if (!is_string_type_valid(comp_ver_str_type)) {
1772 return PLDM_ERROR_INVALID_DATA;
1773 }
1774
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301775 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301776 header.instance = instance_id;
1777 header.msg_type = PLDM_REQUEST;
1778 header.pldm_type = PLDM_FWUP;
1779 header.command = PLDM_PASS_COMPONENT_TABLE;
1780 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1781 if (rc) {
1782 return rc;
1783 }
1784
1785 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301786 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301787
1788 request->transfer_flag = transfer_flag;
1789 request->comp_classification = htole16(comp_classification);
1790 request->comp_identifier = htole16(comp_identifier);
1791 request->comp_classification_index = comp_classification_index;
1792 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1793 request->comp_ver_str_type = comp_ver_str_type;
1794 request->comp_ver_str_len = comp_ver_str_len;
1795
1796 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
1797 comp_ver_str->ptr, comp_ver_str->length);
1798
1799 return PLDM_SUCCESS;
1800}
1801
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001802LIBPLDM_ABI_TESTING
1803int decode_pass_component_table_req(
1804 const struct pldm_msg *msg, size_t payload_length,
1805 struct pldm_pass_component_table_req_full *pcomp)
1806{
1807 int rc;
1808 uint8_t t;
1809 struct pldm_msgbuf _buf;
1810 struct pldm_msgbuf *buf = &_buf;
1811
1812 if (msg == NULL || pcomp == NULL) {
1813 return -EINVAL;
1814 }
1815
1816 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1817 if (rc) {
1818 return rc;
1819 }
1820
1821 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
1822 pldm_msgbuf_extract(buf, pcomp->comp_classification);
1823 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
1824 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
1825 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
1826 rc = pldm_msgbuf_extract(buf, t);
1827 if (rc) {
1828 return rc;
1829 }
1830 if (t > PLDM_STR_TYPE_UTF_16BE) {
1831 return -EBADMSG;
1832 }
1833 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
1834 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
1835 if (rc) {
1836 return rc;
1837 }
1838 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
1839 pcomp->version.str_data,
1840 PLDM_FIRMWARE_MAX_STRING);
1841 if (rc) {
1842 return rc;
1843 }
1844
1845 return pldm_msgbuf_destroy_consumed(buf);
1846}
1847
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301848LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301849int decode_pass_component_table_resp(const struct pldm_msg *msg,
1850 const size_t payload_length,
1851 uint8_t *completion_code,
1852 uint8_t *comp_resp,
1853 uint8_t *comp_resp_code)
1854{
1855 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
1856 comp_resp_code == NULL || !payload_length) {
1857 return PLDM_ERROR_INVALID_DATA;
1858 }
1859
1860 *completion_code = msg->payload[0];
1861 if (*completion_code != PLDM_SUCCESS) {
1862 return PLDM_SUCCESS;
1863 }
1864
1865 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
1866 return PLDM_ERROR_INVALID_LENGTH;
1867 }
1868
1869 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301870 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301871
1872 if (!is_comp_resp_valid(response->comp_resp)) {
1873 return PLDM_ERROR_INVALID_DATA;
1874 }
1875
1876 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
1877 return PLDM_ERROR_INVALID_DATA;
1878 }
1879
1880 *comp_resp = response->comp_resp;
1881 *comp_resp_code = response->comp_resp_code;
1882
1883 return PLDM_SUCCESS;
1884}
1885
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001886LIBPLDM_ABI_TESTING
1887int encode_pass_component_table_resp(
1888 uint8_t instance_id,
1889 const struct pldm_pass_component_table_resp *resp_data,
1890 struct pldm_msg *msg, size_t *payload_length)
1891{
1892 int rc;
1893 struct pldm_msgbuf _buf;
1894 struct pldm_msgbuf *buf = &_buf;
1895
1896 if (msg == NULL || payload_length == NULL) {
1897 return -EINVAL;
1898 }
1899
1900 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1901 PLDM_PASS_COMPONENT_TABLE, msg);
1902 if (rc) {
1903 return -EINVAL;
1904 }
1905
1906 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1907 if (rc) {
1908 return rc;
1909 }
1910
1911 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1912 pldm_msgbuf_insert(buf, resp_data->comp_resp);
1913 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
1914
1915 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
1916}
1917
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301918LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301919int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301920 uint8_t instance_id, uint16_t comp_classification,
1921 uint16_t comp_identifier, uint8_t comp_classification_index,
1922 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
1923 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
1924 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
1925 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301926{
1927 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1928 return PLDM_ERROR_INVALID_DATA;
1929 }
1930
1931 if (payload_length !=
1932 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
1933 return PLDM_ERROR_INVALID_LENGTH;
1934 }
1935
1936 if (!comp_image_size) {
1937 return PLDM_ERROR_INVALID_DATA;
1938 }
1939
1940 if ((comp_ver_str_len == 0) ||
1941 (comp_ver_str_len != comp_ver_str->length)) {
1942 return PLDM_ERROR_INVALID_DATA;
1943 }
1944
1945 if (!is_string_type_valid(comp_ver_str_type)) {
1946 return PLDM_ERROR_INVALID_DATA;
1947 }
1948
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301949 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301950 header.instance = instance_id;
1951 header.msg_type = PLDM_REQUEST;
1952 header.pldm_type = PLDM_FWUP;
1953 header.command = PLDM_UPDATE_COMPONENT;
1954 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1955 if (rc) {
1956 return rc;
1957 }
1958
1959 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301960 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301961
1962 request->comp_classification = htole16(comp_classification);
1963 request->comp_identifier = htole16(comp_identifier);
1964 request->comp_classification_index = comp_classification_index;
1965 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1966 request->comp_image_size = htole32(comp_image_size);
1967 request->update_option_flags.value = htole32(update_option_flags.value);
1968 request->comp_ver_str_type = comp_ver_str_type;
1969 request->comp_ver_str_len = comp_ver_str_len;
1970
1971 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
1972 comp_ver_str->ptr, comp_ver_str->length);
1973
1974 return PLDM_SUCCESS;
1975}
1976
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001977LIBPLDM_ABI_TESTING
1978int decode_update_component_req(const struct pldm_msg *msg,
1979 size_t payload_length,
1980 struct pldm_update_component_req_full *up)
1981{
1982 int rc;
1983 uint8_t t;
1984 struct pldm_msgbuf _buf;
1985 struct pldm_msgbuf *buf = &_buf;
1986
1987 if (msg == NULL || up == NULL) {
1988 return -EINVAL;
1989 }
1990
1991 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1992 if (rc) {
1993 return rc;
1994 }
1995
1996 pldm_msgbuf_extract(buf, up->comp_classification);
1997 pldm_msgbuf_extract(buf, up->comp_identifier);
1998 pldm_msgbuf_extract(buf, up->comp_classification_index);
1999 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2000 pldm_msgbuf_extract(buf, up->comp_image_size);
2001 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2002 rc = pldm_msgbuf_extract(buf, t);
2003 if (rc) {
2004 return rc;
2005 }
2006 if (t > PLDM_STR_TYPE_UTF_16BE) {
2007 return -EBADMSG;
2008 }
2009 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2010 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2011 if (rc) {
2012 return rc;
2013 }
2014 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2015 up->version.str_data,
2016 PLDM_FIRMWARE_MAX_STRING);
2017 if (rc) {
2018 return rc;
2019 }
2020
2021 if (buf->remaining != 0) {
2022 return -EINVAL;
2023 }
2024
2025 return 0;
2026}
2027
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302028LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302029int decode_update_component_resp(const struct pldm_msg *msg,
2030 size_t payload_length,
2031 uint8_t *completion_code,
2032 uint8_t *comp_compatibility_resp,
2033 uint8_t *comp_compatibility_resp_code,
2034 bitfield32_t *update_option_flags_enabled,
2035 uint16_t *time_before_req_fw_data)
2036{
2037 if (msg == NULL || completion_code == NULL ||
2038 comp_compatibility_resp == NULL ||
2039 comp_compatibility_resp_code == NULL ||
2040 update_option_flags_enabled == NULL ||
2041 time_before_req_fw_data == NULL || !payload_length) {
2042 return PLDM_ERROR_INVALID_DATA;
2043 }
2044
2045 *completion_code = msg->payload[0];
2046 if (*completion_code != PLDM_SUCCESS) {
2047 return PLDM_SUCCESS;
2048 }
2049
2050 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2051 return PLDM_ERROR_INVALID_LENGTH;
2052 }
2053
2054 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302055 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302056
2057 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302058 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302059 return PLDM_ERROR_INVALID_DATA;
2060 }
2061
2062 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302063 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302064 return PLDM_ERROR_INVALID_DATA;
2065 }
2066
2067 *comp_compatibility_resp = response->comp_compatibility_resp;
2068 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2069 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302070 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302071 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2072
2073 return PLDM_SUCCESS;
2074}
2075
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002076LIBPLDM_ABI_TESTING
2077int encode_update_component_resp(
2078 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2079 struct pldm_msg *msg, size_t *payload_length)
2080{
2081 int rc;
2082 struct pldm_msgbuf _buf;
2083 struct pldm_msgbuf *buf = &_buf;
2084
2085 if (msg == NULL || payload_length == NULL) {
2086 return -EINVAL;
2087 }
2088
2089 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2090 PLDM_UPDATE_COMPONENT, msg);
2091 if (rc) {
2092 return -EINVAL;
2093 }
2094
2095 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2096 if (rc) {
2097 return rc;
2098 }
2099
2100 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2101 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2102 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2103 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2104 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2105
2106 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2107}
2108
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302109LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302110int decode_request_firmware_data_req(const struct pldm_msg *msg,
2111 size_t payload_length, uint32_t *offset,
2112 uint32_t *length)
2113{
2114 if (msg == NULL || offset == NULL || length == NULL) {
2115 return PLDM_ERROR_INVALID_DATA;
2116 }
2117 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2118 return PLDM_ERROR_INVALID_LENGTH;
2119 }
2120 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302121 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302122 *offset = le32toh(request->offset);
2123 *length = le32toh(request->length);
2124
2125 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2126 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2127 }
2128
2129 return PLDM_SUCCESS;
2130}
2131
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002132LIBPLDM_ABI_TESTING
2133int encode_request_firmware_data_req(
2134 uint8_t instance_id,
2135 const struct pldm_request_firmware_data_req *req_params,
2136 struct pldm_msg *msg, size_t *payload_length)
2137{
2138 int rc;
2139 struct pldm_msgbuf _buf;
2140 struct pldm_msgbuf *buf = &_buf;
2141
2142 if (msg == NULL || payload_length == NULL) {
2143 return -EINVAL;
2144 }
2145
2146 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2147 PLDM_REQUEST_FIRMWARE_DATA, msg);
2148 if (rc) {
2149 return -EINVAL;
2150 }
2151
2152 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2153 if (rc) {
2154 return rc;
2155 }
2156
2157 pldm_msgbuf_insert(buf, req_params->offset);
2158 pldm_msgbuf_insert(buf, req_params->length);
2159
2160 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2161}
2162
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302163LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302164int encode_request_firmware_data_resp(uint8_t instance_id,
2165 uint8_t completion_code,
2166 struct pldm_msg *msg,
2167 size_t payload_length)
2168{
2169 if (msg == NULL || !payload_length) {
2170 return PLDM_ERROR_INVALID_DATA;
2171 }
2172
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302173 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302174 header.instance = instance_id;
2175 header.msg_type = PLDM_RESPONSE;
2176 header.pldm_type = PLDM_FWUP;
2177 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2178 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2179 if (rc) {
2180 return rc;
2181 }
2182
2183 msg->payload[0] = completion_code;
2184
2185 return PLDM_SUCCESS;
2186}
2187
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302188LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302189int decode_transfer_complete_req(const struct pldm_msg *msg,
2190 size_t payload_length,
2191 uint8_t *transfer_result)
2192{
2193 if (msg == NULL || transfer_result == NULL) {
2194 return PLDM_ERROR_INVALID_DATA;
2195 }
2196
2197 if (payload_length != sizeof(*transfer_result)) {
2198 return PLDM_ERROR_INVALID_LENGTH;
2199 }
2200
2201 *transfer_result = msg->payload[0];
2202 return PLDM_SUCCESS;
2203}
2204
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002205LIBPLDM_ABI_TESTING
2206int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2207 struct pldm_msg *msg, size_t *payload_length)
2208{
2209 int rc;
2210 struct pldm_msgbuf _buf;
2211 struct pldm_msgbuf *buf = &_buf;
2212
2213 if (msg == NULL || payload_length == NULL) {
2214 return -EINVAL;
2215 }
2216
2217 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2218 PLDM_TRANSFER_COMPLETE, msg);
2219 if (rc) {
2220 return -EINVAL;
2221 }
2222
2223 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2224 if (rc) {
2225 return rc;
2226 }
2227
2228 rc = pldm_msgbuf_insert(buf, transfer_result);
2229 if (rc) {
2230 return rc;
2231 }
2232
2233 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2234}
2235
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302236LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302237int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2238 struct pldm_msg *msg, size_t payload_length)
2239{
2240 if (msg == NULL) {
2241 return PLDM_ERROR_INVALID_DATA;
2242 }
2243
2244 if (payload_length != sizeof(completion_code)) {
2245 return PLDM_ERROR_INVALID_LENGTH;
2246 }
2247
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302248 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302249 header.instance = instance_id;
2250 header.msg_type = PLDM_RESPONSE;
2251 header.pldm_type = PLDM_FWUP;
2252 header.command = PLDM_TRANSFER_COMPLETE;
2253 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2254 if (rc) {
2255 return rc;
2256 }
2257
2258 msg->payload[0] = completion_code;
2259
2260 return PLDM_SUCCESS;
2261}
2262
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302263LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302264int decode_verify_complete_req(const struct pldm_msg *msg,
2265 size_t payload_length, uint8_t *verify_result)
2266{
2267 if (msg == NULL || verify_result == NULL) {
2268 return PLDM_ERROR_INVALID_DATA;
2269 }
2270
2271 if (payload_length != sizeof(*verify_result)) {
2272 return PLDM_ERROR_INVALID_LENGTH;
2273 }
2274
2275 *verify_result = msg->payload[0];
2276 return PLDM_SUCCESS;
2277}
2278
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002279LIBPLDM_ABI_TESTING
2280int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2281 struct pldm_msg *msg, size_t *payload_length)
2282{
2283 int rc;
2284 struct pldm_msgbuf _buf;
2285 struct pldm_msgbuf *buf = &_buf;
2286
2287 if (msg == NULL || payload_length == NULL) {
2288 return -EINVAL;
2289 }
2290
2291 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2292 PLDM_VERIFY_COMPLETE, msg);
2293 if (rc) {
2294 return EINVAL;
2295 }
2296
2297 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2298 if (rc) {
2299 return rc;
2300 }
2301
2302 rc = pldm_msgbuf_insert(buf, verify_result);
2303 if (rc) {
2304 return rc;
2305 }
2306
2307 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2308}
2309
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302310LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302311int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2312 struct pldm_msg *msg, size_t payload_length)
2313{
2314 if (msg == NULL) {
2315 return PLDM_ERROR_INVALID_DATA;
2316 }
2317
2318 if (payload_length != sizeof(completion_code)) {
2319 return PLDM_ERROR_INVALID_LENGTH;
2320 }
2321
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302322 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302323 header.instance = instance_id;
2324 header.msg_type = PLDM_RESPONSE;
2325 header.pldm_type = PLDM_FWUP;
2326 header.command = PLDM_VERIFY_COMPLETE;
2327 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2328 if (rc) {
2329 return rc;
2330 }
2331
2332 msg->payload[0] = completion_code;
2333
2334 return PLDM_SUCCESS;
2335}
2336
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302337LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302338int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2339 uint8_t *apply_result,
2340 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302341{
2342 if (msg == NULL || apply_result == NULL ||
2343 comp_activation_methods_modification == NULL) {
2344 return PLDM_ERROR_INVALID_DATA;
2345 }
2346
2347 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2348 return PLDM_ERROR_INVALID_LENGTH;
2349 }
2350
2351 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302352 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302353
2354 *apply_result = request->apply_result;
2355 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302356 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302357
2358 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2359 comp_activation_methods_modification->value) {
2360 return PLDM_ERROR_INVALID_DATA;
2361 }
2362
2363 return PLDM_SUCCESS;
2364}
2365
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002366LIBPLDM_ABI_TESTING
2367int encode_apply_complete_req(uint8_t instance_id,
2368 const struct pldm_apply_complete_req *req_data,
2369 struct pldm_msg *msg, size_t *payload_length)
2370{
2371 int rc;
2372 struct pldm_msgbuf _buf;
2373 struct pldm_msgbuf *buf = &_buf;
2374
2375 if (msg == NULL || payload_length == NULL) {
2376 return -EINVAL;
2377 }
2378
2379 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2380 PLDM_APPLY_COMPLETE, msg);
2381 if (rc) {
2382 return -EINVAL;
2383 }
2384
2385 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2386 if (rc) {
2387 return rc;
2388 }
2389
2390 pldm_msgbuf_insert(buf, req_data->apply_result);
2391 pldm_msgbuf_insert(
2392 buf, req_data->comp_activation_methods_modification.value);
2393
2394 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2395}
2396
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302397LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302398int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2399 struct pldm_msg *msg, size_t payload_length)
2400{
2401 if (msg == NULL) {
2402 return PLDM_ERROR_INVALID_DATA;
2403 }
2404
2405 if (payload_length != sizeof(completion_code)) {
2406 return PLDM_ERROR_INVALID_LENGTH;
2407 }
2408
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302409 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302410 header.instance = instance_id;
2411 header.msg_type = PLDM_RESPONSE;
2412 header.pldm_type = PLDM_FWUP;
2413 header.command = PLDM_APPLY_COMPLETE;
2414 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2415 if (rc) {
2416 return rc;
2417 }
2418
2419 msg->payload[0] = completion_code;
2420
2421 return PLDM_SUCCESS;
2422}
2423
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002424LIBPLDM_ABI_TESTING
2425int decode_activate_firmware_req(const struct pldm_msg *msg,
2426 size_t payload_length, bool *self_contained)
2427{
2428 int rc;
2429 struct pldm_msgbuf _buf;
2430 struct pldm_msgbuf *buf = &_buf;
2431
2432 if (msg == NULL || self_contained == NULL) {
2433 return -EINVAL;
2434 }
2435
2436 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2437 if (rc) {
2438 return 0;
2439 }
2440
2441 uint8_t self_contained_u8 = 0;
2442 rc = pldm_msgbuf_extract(buf, self_contained_u8);
2443 if (rc) {
2444 return rc;
2445 }
2446 if (buf->remaining != 0) {
2447 return -EOVERFLOW;
2448 }
2449 *self_contained = (bool)self_contained_u8;
2450 return 0;
2451}
2452
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302453LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302454int encode_activate_firmware_req(uint8_t instance_id,
2455 bool8_t self_contained_activation_req,
2456 struct pldm_msg *msg, size_t payload_length)
2457{
2458 if (msg == NULL) {
2459 return PLDM_ERROR_INVALID_DATA;
2460 }
2461
2462 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2463 return PLDM_ERROR_INVALID_LENGTH;
2464 }
2465
2466 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302467 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302468 return PLDM_ERROR_INVALID_DATA;
2469 }
2470
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302471 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302472 header.instance = instance_id;
2473 header.msg_type = PLDM_REQUEST;
2474 header.pldm_type = PLDM_FWUP;
2475 header.command = PLDM_ACTIVATE_FIRMWARE;
2476 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2477 if (rc) {
2478 return rc;
2479 }
2480
2481 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302482 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302483
2484 request->self_contained_activation_req = self_contained_activation_req;
2485
2486 return PLDM_SUCCESS;
2487}
2488
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302489LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302490int decode_activate_firmware_resp(const struct pldm_msg *msg,
2491 size_t payload_length,
2492 uint8_t *completion_code,
2493 uint16_t *estimated_time_activation)
2494{
2495 if (msg == NULL || completion_code == NULL ||
2496 estimated_time_activation == NULL || !payload_length) {
2497 return PLDM_ERROR_INVALID_DATA;
2498 }
2499
2500 *completion_code = msg->payload[0];
2501 if (*completion_code != PLDM_SUCCESS) {
2502 return PLDM_SUCCESS;
2503 }
2504
2505 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2506 return PLDM_ERROR_INVALID_LENGTH;
2507 }
2508
2509 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302510 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302511
2512 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302513 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302514
2515 return PLDM_SUCCESS;
2516}
2517
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002518LIBPLDM_ABI_TESTING
2519int encode_activate_firmware_resp(
2520 uint8_t instance_id,
2521 const struct pldm_activate_firmware_resp *resp_data,
2522 struct pldm_msg *msg, size_t *payload_length)
2523{
2524 int rc;
2525 struct pldm_msgbuf _buf;
2526 struct pldm_msgbuf *buf = &_buf;
2527
2528 if (msg == NULL || payload_length == NULL) {
2529 return -EINVAL;
2530 }
2531
2532 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2533 PLDM_ACTIVATE_FIRMWARE, msg);
2534 if (rc) {
2535 return -EINVAL;
2536 }
2537
2538 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2539 if (rc) {
2540 return rc;
2541 }
2542
2543 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2544 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2545
2546 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2547}
2548
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302549LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302550int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2551 size_t payload_length)
2552{
2553 if (msg == NULL) {
2554 return PLDM_ERROR_INVALID_DATA;
2555 }
2556
2557 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2558 return PLDM_ERROR_INVALID_LENGTH;
2559 }
2560
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302561 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302562 header.instance = instance_id;
2563 header.msg_type = PLDM_REQUEST;
2564 header.pldm_type = PLDM_FWUP;
2565 header.command = PLDM_GET_STATUS;
2566 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2567 if (rc) {
2568 return rc;
2569 }
2570
2571 return PLDM_SUCCESS;
2572}
2573
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302574LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302575int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2576 uint8_t *completion_code, uint8_t *current_state,
2577 uint8_t *previous_state, uint8_t *aux_state,
2578 uint8_t *aux_state_status, uint8_t *progress_percent,
2579 uint8_t *reason_code,
2580 bitfield32_t *update_option_flags_enabled)
2581{
2582 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2583 previous_state == NULL || aux_state == NULL ||
2584 aux_state_status == NULL || progress_percent == NULL ||
2585 reason_code == NULL || update_option_flags_enabled == NULL ||
2586 !payload_length) {
2587 return PLDM_ERROR_INVALID_DATA;
2588 }
2589
2590 *completion_code = msg->payload[0];
2591 if (*completion_code != PLDM_SUCCESS) {
2592 return PLDM_SUCCESS;
2593 }
2594
2595 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2596 return PLDM_ERROR_INVALID_LENGTH;
2597 }
2598 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302599 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302600
2601 if (!is_state_valid(response->current_state)) {
2602 return PLDM_ERROR_INVALID_DATA;
2603 }
2604 if (!is_state_valid(response->previous_state)) {
2605 return PLDM_ERROR_INVALID_DATA;
2606 }
2607 if (!is_aux_state_valid(response->aux_state)) {
2608 return PLDM_ERROR_INVALID_DATA;
2609 }
2610 if (!is_aux_state_status_valid(response->aux_state_status)) {
2611 return PLDM_ERROR_INVALID_DATA;
2612 }
2613 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2614 return PLDM_ERROR_INVALID_DATA;
2615 }
2616 if (!is_reason_code_valid(response->reason_code)) {
2617 return PLDM_ERROR_INVALID_DATA;
2618 }
2619
2620 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2621 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2622 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2623 if (response->aux_state !=
2624 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2625 return PLDM_ERROR_INVALID_DATA;
2626 }
2627 }
2628
2629 *current_state = response->current_state;
2630 *previous_state = response->previous_state;
2631 *aux_state = response->aux_state;
2632 *aux_state_status = response->aux_state_status;
2633 *progress_percent = response->progress_percent;
2634 *reason_code = response->reason_code;
2635 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302636 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302637
2638 return PLDM_SUCCESS;
2639}
2640
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002641LIBPLDM_ABI_TESTING
2642int encode_get_status_resp(uint8_t instance_id,
2643 const struct pldm_get_status_resp *status,
2644 struct pldm_msg *msg, size_t *payload_length)
2645{
2646 int rc;
2647 struct pldm_msgbuf _buf;
2648 struct pldm_msgbuf *buf = &_buf;
2649
2650 if (status == NULL || msg == NULL || payload_length == NULL) {
2651 return -EINVAL;
2652 }
2653
2654 if (status->completion_code != PLDM_SUCCESS) {
2655 return -EINVAL;
2656 }
2657
2658 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2659 PLDM_GET_STATUS, msg);
2660 if (rc) {
2661 return -EINVAL;
2662 }
2663
2664 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2665 if (rc) {
2666 return rc;
2667 }
2668
2669 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2670 pldm_msgbuf_insert(buf, status->current_state);
2671 pldm_msgbuf_insert(buf, status->previous_state);
2672 pldm_msgbuf_insert(buf, status->aux_state);
2673 pldm_msgbuf_insert(buf, status->aux_state_status);
2674 pldm_msgbuf_insert(buf, status->progress_percent);
2675 pldm_msgbuf_insert(buf, status->reason_code);
2676 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
2677
2678 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2679}
2680
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302681LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302682int encode_cancel_update_component_req(uint8_t instance_id,
2683 struct pldm_msg *msg,
2684 size_t payload_length)
2685{
2686 if (msg == NULL) {
2687 return PLDM_ERROR_INVALID_DATA;
2688 }
2689
2690 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
2691 return PLDM_ERROR_INVALID_LENGTH;
2692 }
2693
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302694 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302695 header.instance = instance_id;
2696 header.msg_type = PLDM_REQUEST;
2697 header.pldm_type = PLDM_FWUP;
2698 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
2699 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2700 if (rc) {
2701 return rc;
2702 }
2703
2704 return PLDM_SUCCESS;
2705}
2706
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302707LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302708int decode_cancel_update_component_resp(const struct pldm_msg *msg,
2709 size_t payload_length,
2710 uint8_t *completion_code)
2711{
2712 if (msg == NULL || completion_code == NULL) {
2713 return PLDM_ERROR_INVALID_DATA;
2714 }
2715
2716 if (payload_length != sizeof(*completion_code)) {
2717 return PLDM_ERROR_INVALID_LENGTH;
2718 }
2719
2720 *completion_code = msg->payload[0];
2721 return PLDM_SUCCESS;
2722}
2723
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302724LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302725int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
2726 size_t payload_length)
2727{
2728 if (msg == NULL) {
2729 return PLDM_ERROR_INVALID_DATA;
2730 }
2731
2732 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
2733 return PLDM_ERROR_INVALID_LENGTH;
2734 }
2735
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302736 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302737 header.instance = instance_id;
2738 header.msg_type = PLDM_REQUEST;
2739 header.pldm_type = PLDM_FWUP;
2740 header.command = PLDM_CANCEL_UPDATE;
2741 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2742 if (rc) {
2743 return rc;
2744 }
2745
2746 return PLDM_SUCCESS;
2747}
2748
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302749LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302750int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
2751 uint8_t *completion_code,
2752 bool8_t *non_functioning_component_indication,
2753 bitfield64_t *non_functioning_component_bitmap)
2754{
2755 if (msg == NULL || completion_code == NULL ||
2756 non_functioning_component_indication == NULL ||
2757 non_functioning_component_bitmap == NULL || !payload_length) {
2758 return PLDM_ERROR_INVALID_DATA;
2759 }
2760
2761 *completion_code = msg->payload[0];
2762 if (*completion_code != PLDM_SUCCESS) {
2763 return PLDM_SUCCESS;
2764 }
2765
2766 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
2767 return PLDM_ERROR_INVALID_LENGTH;
2768 }
2769 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302770 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302771
2772 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302773 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302774 return PLDM_ERROR_INVALID_DATA;
2775 }
2776
2777 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302778 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302779
2780 if (*non_functioning_component_indication) {
2781 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302782 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302783 }
2784
2785 return PLDM_SUCCESS;
2786}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002787
2788LIBPLDM_ABI_TESTING
2789int encode_cancel_update_resp(uint8_t instance_id,
2790 const struct pldm_cancel_update_resp *resp_data,
2791 struct pldm_msg *msg, size_t *payload_length)
2792{
2793 int rc;
2794 struct pldm_msgbuf _buf;
2795 struct pldm_msgbuf *buf = &_buf;
2796
2797 if (msg == NULL || payload_length == NULL) {
2798 return -EINVAL;
2799 }
2800
2801 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2802 PLDM_CANCEL_UPDATE, msg);
2803 if (rc) {
2804 return -EINVAL;
2805 }
2806
2807 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2808 if (rc) {
2809 return rc;
2810 }
2811
2812 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2813 pldm_msgbuf_insert(buf,
2814 resp_data->non_functioning_component_indication);
2815 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
2816
2817 return pldm_msgbuf_destroy_used(buf, *payload_length, payload_length);
2818}