dsp: firmware_update: Iterators for downstream device descriptors
Provide an ergonomic and safe means to iterate through downstream
devices and their descriptors while avoiding the need to allocate. The
strategy leaves the library user to make their own choices about how the
data is handled.
The user-facing portion of the change takes the form of two new macros,
to be nested inside one another:
```
foreach_pldm_downstream_device(...) {
foreach_pldm_downstream_device_descriptor(...) {
// Do something with the device-specific descriptor
}
}
```
Examples uses are provided in the documentation and in changes to the
test suite.
Change-Id: I6e79454b94868da73f318635bcaae57cd51fbf97
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/compiler.h b/src/compiler.h
index 91b6e24..18e1a32 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -2,6 +2,8 @@
#ifndef PLDM_COMPILER_H
#define PLDM_COMPILER_H
+#include <libpldm/compiler.h>
+
#ifndef __has_attribute
#error The libpldm implementation requires __has_attribute
#endif
@@ -20,8 +22,14 @@
int compliance;
} pldm_required_attributes __attribute__((unused));
-#define LIBPLDM_CC_ALWAYS_INLINE __attribute__((always_inline)) static inline
-#define LIBPLDM_CC_NONNULL __attribute__((nonnull))
+#ifndef LIBPLDM_CC_ALWAYS_INLINE
+#error Missing definition for LIBPLDM_ALWAYS_INLINE
+#endif
+
+#ifndef LIBPLDM_CC_NONNULL
+#error Missing definition for LIBPLDM_CC_NONNULL
+#endif
+
#define LIBPLDM_CC_NONNULL_ARGS(...) __attribute__((nonnull(__VA_ARGS__)))
#define LIBPLDM_CC_UNUSED __attribute__((unused))
#define LIBPLDM_CC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
diff --git a/src/dsp/firmware_update.c b/src/dsp/firmware_update.c
index 2afcaab..d570d5c 100644
--- a/src/dsp/firmware_update.c
+++ b/src/dsp/firmware_update.c
@@ -473,6 +473,40 @@
return PLDM_SUCCESS;
}
+LIBPLDM_ABI_TESTING
+int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
+ struct pldm_descriptor *desc)
+{
+ struct pldm_msgbuf _buf;
+ struct pldm_msgbuf *buf = &_buf;
+ int rc;
+
+ if (!iter || !iter->field || !desc) {
+ return -EINVAL;
+ }
+
+ rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
+ iter->field->ptr, iter->field->length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_extract(buf, desc->descriptor_type);
+ rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
+ if (rc) {
+ return rc;
+ }
+
+ desc->descriptor_data = NULL;
+ pldm_msgbuf_span_required(buf, desc->descriptor_length,
+ (void **)&desc->descriptor_data);
+ iter->field->ptr = NULL;
+ pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
+ &iter->field->length);
+
+ return pldm_msgbuf_destroy(buf);
+}
+
LIBPLDM_ABI_STABLE
int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
uint16_t *descriptor_type,
@@ -998,13 +1032,14 @@
int decode_query_downstream_identifiers_resp(
const struct pldm_msg *msg, size_t payload_length,
struct pldm_query_downstream_identifiers_resp *resp_data,
- struct variable_field *downstream_devices)
+ struct pldm_downstream_device_iter *iter)
{
struct pldm_msgbuf _buf;
struct pldm_msgbuf *buf = &_buf;
+ void *remaining = NULL;
int rc = PLDM_ERROR;
- if (msg == NULL || resp_data == NULL || downstream_devices == NULL ||
+ if (msg == NULL || resp_data == NULL || iter == NULL ||
!payload_length) {
return PLDM_ERROR_INVALID_DATA;
}
@@ -1036,23 +1071,53 @@
}
pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
- rc = pldm_msgbuf_span_required(buf,
- resp_data->downstream_devices_length,
- (void **)&downstream_devices->ptr);
+ rc = pldm_msgbuf_span_required(
+ buf, resp_data->downstream_devices_length, &remaining);
if (rc) {
return pldm_xlate_errno(rc);
}
- downstream_devices->length = resp_data->downstream_devices_length;
rc = pldm_msgbuf_destroy(buf);
if (rc) {
return pldm_xlate_errno(rc);
}
+ iter->field.ptr = remaining;
+ iter->field.length = resp_data->downstream_devices_length;
+ iter->devs = resp_data->number_of_downstream_devices;
+
return PLDM_SUCCESS;
}
LIBPLDM_ABI_TESTING
+int decode_pldm_downstream_device_from_iter(
+ struct pldm_downstream_device_iter *iter,
+ struct pldm_downstream_device *dev)
+{
+ struct pldm_msgbuf _buf;
+ struct pldm_msgbuf *buf = &_buf;
+ int rc;
+
+ if (!iter || !dev) {
+ return -EINVAL;
+ }
+
+ rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
+ iter->field.length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_extract(buf, dev->downstream_device_index);
+ pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
+ iter->field.ptr = NULL;
+ pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+ &iter->field.length);
+
+ return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_TESTING
int encode_get_downstream_firmware_params_req(
uint8_t instance_id, uint32_t data_transfer_handle,
enum transfer_op_flag transfer_operation_flag, struct pldm_msg *msg,