pdr: Add related decode_entity_auxiliary_names_pdr*() APIs
Add `decode_entity_auxiliary_names_pdr()` to decode the entity auxiliary
names PDR raw data to the data fields as table 95 in DSP0248_1.2.2.
The API will not decode the entity auxiliary names directly - to
expose the language tags and names fields the caller has to
subsequently call `decode_pldm_entity_auxiliary_names_pdr_index()`.
Between the API calls the caller must allocate memory for the
`names` field as an array of `struct pldm_entity_auxiliary_name` with
`name_string_count` elements.
Change-Id: I5fc3989c4c4595546a70c01eb2b6dadcf8c14303
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/dsp/platform.c b/src/dsp/platform.c
index c9251dc..3d27802 100644
--- a/src/dsp/platform.c
+++ b/src/dsp/platform.c
@@ -11,6 +11,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <uchar.h>
static int pldm_platform_pdr_hdr_validate(struct pldm_value_pdr_hdr *ctx,
size_t lower, size_t upper)
@@ -2691,3 +2692,176 @@
return pldm_msgbuf_destroy_consumed(buf);
}
+
+LIBPLDM_ABI_TESTING
+int decode_entity_auxiliary_names_pdr(
+ const void *data, size_t data_length,
+ struct pldm_entity_auxiliary_names_pdr *pdr, size_t pdr_length)
+{
+ struct pldm_msgbuf _buf;
+ struct pldm_msgbuf *buf = &_buf;
+ struct pldm_msgbuf _src;
+ struct pldm_msgbuf *src = &_src;
+ struct pldm_msgbuf _dst;
+ struct pldm_msgbuf *dst = &_dst;
+ size_t names_len = 0;
+ void *names = NULL;
+ int rc;
+ int i;
+
+ /*
+ * Alignment of auxiliary_name_data is an invariant as we statically assert
+ * its behaviour in the header.
+ */
+ assert(!((uintptr_t)pdr->auxiliary_name_data &
+ (alignof(pldm_utf16be) - 1)));
+
+ /* Reject any lengths that are obviously invalid */
+ if (pdr_length < data_length || pdr_length < sizeof(*pdr)) {
+ return -EINVAL;
+ }
+
+ rc = pldm_msgbuf_init_errno(
+ buf, PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH, data,
+ data_length);
+ if (rc) {
+ return rc;
+ }
+
+ rc = pldm_msgbuf_extract_value_pdr_hdr(buf, &pdr->hdr);
+ if (rc) {
+ return rc;
+ }
+
+ rc = pldm_platform_pdr_hdr_validate(
+ &pdr->hdr, PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH,
+ data_length);
+ if (rc) {
+ return rc;
+ }
+
+ pldm_msgbuf_extract(buf, pdr->container.entity_type);
+ pldm_msgbuf_extract(buf, pdr->container.entity_instance_num);
+ pldm_msgbuf_extract(buf, pdr->container.entity_container_id);
+ pldm_msgbuf_extract(buf, pdr->shared_name_count);
+ rc = pldm_msgbuf_extract(buf, pdr->name_string_count);
+ if (rc < 0) {
+ return rc;
+ }
+
+ rc = pldm_msgbuf_span_remaining(buf, &names, &names_len);
+ if (rc < 0) {
+ return rc;
+ }
+
+ pdr->auxiliary_name_data_size = pdr_length - sizeof(*pdr);
+
+ rc = pldm_msgbuf_init_errno(dst, pdr->auxiliary_name_data_size,
+ pdr->auxiliary_name_data,
+ pdr->auxiliary_name_data_size);
+ if (rc < 0) {
+ return rc;
+ }
+
+ /*
+ * Below we do two passes over the same region. This is to first pack the
+ * UTF16-BE strings into auxiliary_name_data, followed by the ASCII strings,
+ * to maintain appropriate alignment.
+ */
+
+ /* Initialise for the first pass to extract the UTF16-BE name strings */
+ rc = pldm_msgbuf_init_errno(src, names_len, names, names_len);
+ if (rc < 0) {
+ return rc;
+ }
+
+ for (i = 0; i < pdr->name_string_count; i++) {
+ pldm_msgbuf_span_string_ascii(src, NULL, NULL);
+ pldm_msgbuf_copy_string_utf16(dst, src);
+ }
+
+ rc = pldm_msgbuf_destroy_consumed(src);
+ if (rc < 0) {
+ return rc;
+ }
+
+ /* Reinitialise for the second pass to extract the ASCII tag strings */
+ rc = pldm_msgbuf_init_errno(src, names_len, names, names_len);
+ if (rc < 0) {
+ return rc;
+ }
+
+ for (i = 0; i < pdr->name_string_count; i++) {
+ pldm_msgbuf_copy_string_ascii(dst, src);
+ pldm_msgbuf_span_string_utf16(src, NULL, NULL);
+ }
+
+ if ((rc = pldm_msgbuf_destroy(dst)) ||
+ (rc = pldm_msgbuf_destroy(src)) ||
+ (rc = pldm_msgbuf_destroy(buf))) {
+ return rc;
+ }
+
+ return 0;
+}
+
+LIBPLDM_ABI_TESTING
+int decode_pldm_entity_auxiliary_names_pdr_index(
+ struct pldm_entity_auxiliary_names_pdr *pdr)
+{
+ struct pldm_msgbuf _buf;
+ struct pldm_msgbuf *buf = &_buf;
+ int rc;
+ int i;
+
+ if (!pdr) {
+ return -EINVAL;
+ }
+
+ if (pdr->name_string_count == 0 && pdr->names) {
+ return -EINVAL;
+ }
+
+ if (pdr->name_string_count > 0 && !pdr->names) {
+ return -EINVAL;
+ }
+
+ if (pdr->name_string_count == 0) {
+ return 0;
+ }
+
+ /*
+ * Minimum size is one NUL for each member of each entry
+ *
+ * Note that the definition of nameLanguageTag in DSP0248 v1.2.2
+ * states the following:
+ *
+ * > A null-terminated ISO646 ASCII string ...
+ * >
+ * > special value: null string = 0x0000 = unspecified.
+ *
+ * Until proven otherwise we will assume the "0x0000" is a
+ * misrepresentation of an ASCII NUL, and that ASCII NUL is
+ * represented by a single byte.
+ */
+ rc = pldm_msgbuf_init_errno(
+ buf, pdr->name_string_count * (sizeof(char) + sizeof(char16_t)),
+ pdr->auxiliary_name_data, pdr->auxiliary_name_data_size);
+ if (rc) {
+ return rc;
+ }
+
+ for (i = 0; i < pdr->name_string_count; i++) {
+ void *loc = NULL;
+ pldm_msgbuf_span_string_utf16(buf, &loc, NULL);
+ pdr->names[i].name = loc;
+ }
+
+ for (i = 0; i < pdr->name_string_count; i++) {
+ void *loc = NULL;
+ pldm_msgbuf_span_string_ascii(buf, &loc, NULL);
+ pdr->names[i].tag = loc;
+ }
+
+ return pldm_msgbuf_destroy_consumed(buf);
+}