summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Amelkin <alexander@amelkin.msk.ru>2022-12-06 01:12:29 +0300
committerAlexander Amelkin <mocbuhtig@amelkin.msk.ru>2022-12-06 02:48:52 +0300
commitf033b5549e90d7ae05cb5e331d887354f50bf7d6 (patch)
tree5d7a7d94621d18c1e6e54c61c82c83501dd109b5
parent1edb0e27e44196d1ebe449aba0b9be22d376bcb6 (diff)
downloadipmitool-f033b5549e90d7ae05cb5e331d887354f50bf7d6.tar.gz
fru: Add decoder for multirec system mgmt records
* Add a decoder for System Management records in the Multirecord area * Refactor GUID/UUID decoding: Use the same code for `mc guid` and for `fru print` to decode the GUID and System Unique ID in System Management records in the Multirecord Area. * Fix some type errors in calls to printf/sprintf in GUID decoder Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
-rw-r--r--include/ipmitool/ipmi_fru.h40
-rw-r--r--include/ipmitool/ipmi_mc.h15
-rw-r--r--lib/ipmi_fru.c101
-rw-r--r--lib/ipmi_mc.c42
4 files changed, 180 insertions, 18 deletions
diff --git a/include/ipmitool/ipmi_fru.h b/include/ipmitool/ipmi_fru.h
index 4d4d6c6..f301b09 100644
--- a/include/ipmitool/ipmi_fru.h
+++ b/include/ipmitool/ipmi_fru.h
@@ -127,6 +127,7 @@ struct fru_area_product {
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
+/* See Table 16-1 of "IPMI FRU Information Storage Specification" */
struct fru_multirec_header {
#define FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION 0x00
#define FRU_RECORD_TYPE_DC_OUTPUT 0x01
@@ -136,6 +137,8 @@ struct fru_multirec_header {
#define FRU_RECORD_TYPE_EXTENDED_COMPATIBILITY 0x05
#define FRU_RECORD_TYPE_OEM_EXTENSION 0xc0
uint8_t type;
+#define FRU_RECORD_FORMAT_EOL_MASK 0x80
+#define FRU_RECORD_FORMAT_VER_MASK 0x0F
uint8_t format;
uint8_t len;
uint8_t record_checksum;
@@ -242,6 +245,43 @@ struct fru_multirec_dcload {
#endif
#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+/*
+ * In accordance with Table 18-7 of "IPMI Platform Management FRU Information
+ * Storage Definition v1.0"
+ */
+struct fru_multirec_mgmt {
+#define FRU_MULTIREC_MGMT_SUBTYPE_MIN 0x01
+#define FRU_MULTIREC_MGMT_SUBTYPE_MAX 0x07
+ uint8_t subtype;
+#define FRU_MULTIREC_MGMT_SYSURL 0x01
+#define FRU_MULTIREC_MGMT_CMPURL 0x04
+#define FRU_MULTIREC_MGMT_URL_MINLEN 16
+#define FRU_MULTIREC_MGMT_URL_MAXLEN 256
+
+#define FRU_MULTIREC_MGMT_SYSNAME 0x02
+#define FRU_MULTIREC_MGMT_CMPNAME 0x05
+#define FRU_MULTIREC_MGMT_NAME_MINLEN 8
+#define FRU_MULTIREC_MGMT_NAME_MAXLEN 64
+
+#define FRU_MULTIREC_MGMT_SYSPINGADDR 0x03
+#define FRU_MULTIREC_MGMT_CMPPINGADDR 0x06
+#define FRU_MULTIREC_MGMT_PINGADDR_MINLEN 8
+#define FRU_MULTIREC_MGMT_PINGADDR_MAXLEN 64
+
+#define FRU_MULTIREC_MGMT_UUID 0x07
+#define FRU_MULTIREC_MGMT_UUID_LEN 16
+
+#define FRU_MULTIREC_MGMT_DATA_MAXLEN FRU_MULTIREC_MGMT_URL_MAXLEN
+ uint8_t data[];
+} ATTRIBUTE_PACKING;
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
struct fru_multirec_oem_header {
diff --git a/include/ipmitool/ipmi_mc.h b/include/ipmitool/ipmi_mc.h
index 65cba84..fd8c69a 100644
--- a/include/ipmitool/ipmi_mc.h
+++ b/include/ipmitool/ipmi_mc.h
@@ -211,6 +211,21 @@ typedef struct {
parsed_guid_t ipmi_parse_guid(void *guid, ipmi_guid_mode_t guid_mode);
+/**
+ * Convert a binary GUID/UUID to a canonical hex string form.
+ * If the version/encoding of the source data is unknown,
+ * dump the source data as a simple hex string.
+ *
+ * @param[out] str The string representation of GUID
+ * @param[in] data The source binary GUID data
+ * @param[in] mode The conversion mode, use GUID_AUTO for automatic detection
+ *
+ * @returns The parsed GUID structure
+ */
+parsed_guid_t
+ipmi_guid2str(char *str, const void *data, ipmi_guid_mode_t mode);
+#define GUID_STR_MAXLEN 36 /* 8+4+4+4+12 bytes plus the dashes */
+
int _ipmi_mc_get_guid(struct ipmi_intf *intf, ipmi_guid_t *guid);
#ifdef HAVE_PRAGMA_PACK
diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c
index 3d1d8a1..2d8daaf 100644
--- a/lib/ipmi_fru.c
+++ b/lib/ipmi_fru.c
@@ -42,6 +42,7 @@
#include <ipmitool/ipmi_time.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -1283,6 +1284,26 @@ fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru,
free_n(&fru_data);
}
+/**
+ * Take n bytes from src and convert them into hex doublets in dst
+ *
+ * The function is invoked from a place where the dst is known to
+ * have enough space to accomodate the hex string representation
+ * of a UUID.
+ *
+ * @param[out] dst The destination buffer (at least 33 bytes long)
+ * @param[in] src The source binary data
+ * @param[in] n The length of the source data, for compatibility
+ * with strncpy() on calls from fru_area_print_multirec()
+ */
+static
+char *
+uuidstrncpy(char *dst, const char *src, size_t n)
+{
+ (void)ipmi_guid2str(dst, src, GUID_AUTO);
+ return dst;
+}
+
/* fru_area_print_multirec - Print FRU Multi Record Area
*
* @intf: ipmi interface
@@ -1467,8 +1488,86 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru,
}
}
break;
+ case FRU_RECORD_TYPE_MANAGEMENT_ACCESS:
+ {
+ struct fru_multirec_mgmt *mmh =
+ (struct fru_multirect_mgmt *)
+ &fru_data[sizeof(struct fru_multirec_header)];
+ size_t datalen = h->len - sizeof(*mmh);
+ struct {
+ unsigned char *name;
+ size_t minlen;
+ size_t maxlen;
+ char * (*convert)(char *, const char *, size_t);
+ } subtypes[FRU_MULTIREC_MGMT_SUBTYPE_MAX + 1] = {
+ [FRU_MULTIREC_MGMT_SYSURL] = {
+ "System Management URL",
+ FRU_MULTIREC_MGMT_URL_MINLEN,
+ FRU_MULTIREC_MGMT_URL_MAXLEN,
+ strncpy
+ },
+ [FRU_MULTIREC_MGMT_SYSNAME] = {
+ "System Name",
+ FRU_MULTIREC_MGMT_NAME_MINLEN,
+ FRU_MULTIREC_MGMT_NAME_MAXLEN,
+ strncpy
+ },
+ [FRU_MULTIREC_MGMT_SYSPINGADDR] = {
+ "System Ping Address",
+ FRU_MULTIREC_MGMT_PINGADDR_MINLEN,
+ FRU_MULTIREC_MGMT_PINGADDR_MAXLEN,
+ strncpy
+ },
+ [FRU_MULTIREC_MGMT_CMPURL] = {
+ "Component Management URL",
+ FRU_MULTIREC_MGMT_URL_MINLEN,
+ FRU_MULTIREC_MGMT_URL_MAXLEN,
+ strncpy
+ },
+ [FRU_MULTIREC_MGMT_CMPNAME] = {
+ "Component Name",
+ FRU_MULTIREC_MGMT_NAME_MINLEN,
+ FRU_MULTIREC_MGMT_NAME_MAXLEN,
+ strncpy
+ },
+ [FRU_MULTIREC_MGMT_CMPPINGADDR] = {
+ "Component Ping Address",
+ FRU_MULTIREC_MGMT_PINGADDR_MINLEN,
+ FRU_MULTIREC_MGMT_PINGADDR_MAXLEN,
+ strncpy
+ },
+ [FRU_MULTIREC_MGMT_UUID] = {
+ "System Unique ID",
+ FRU_MULTIREC_MGMT_UUID_LEN,
+ FRU_MULTIREC_MGMT_UUID_LEN,
+ uuidstrncpy
+ }
+ };
+ unsigned char string[FRU_MULTIREC_MGMT_DATA_MAXLEN + 1] = { 0 };
+
+ if (mmh->subtype < FRU_MULTIREC_MGMT_SUBTYPE_MIN ||
+ mmh->subtype > FRU_MULTIREC_MGMT_SUBTYPE_MAX)
+ {
+ lprintf(LOG_WARN, "Unsupported subtype 0x%02x found for "
+ "multi-record area management record\n",
+ mmh->subtype);
+ break;
+ }
+
+ if (datalen < subtypes[mmh->subtype].minlen ||
+ datalen > subtypes[mmh->subtype].maxlen)
+ {
+ lprintf(LOG_WARN,
+ "Wrong data length %zu, must be %zu < X < %zu\n",
+ datalen,
+ subtypes[mmh->subtype].minlen,
+ subtypes[mmh->subtype].maxlen);
+ }
+ subtypes[mmh->subtype].convert(string, mmh->data, datalen);
+ printf(" %-22s: %s\n", subtypes[mmh->subtype].name, string);
+ }
}
- } while (!(h->format & 0x80));
+ } while (!(h->format & FRU_RECORD_FORMAT_EOL_MASK));
lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off);
diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c
index a594347..07978f7 100644
--- a/lib/ipmi_mc.c
+++ b/lib/ipmi_mc.c
@@ -696,6 +696,27 @@ out:
return parsed_guid;
}
+parsed_guid_t
+ipmi_guid2str(char *str, const void *data, ipmi_guid_mode_t mode)
+{
+ parsed_guid_t guid;
+ guid = ipmi_parse_guid(data, mode);
+
+ if (GUID_DUMP == guid.mode) {
+ sprintf(str, "%s", buf2str(data, sizeof(ipmi_guid_t)));
+ return guid;
+ }
+
+ sprintf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ (int)guid.time_low,
+ (int)guid.time_mid,
+ (int)guid.time_hi_and_version,
+ (int)guid.clock_seq_and_rsvd,
+ (int)guid.node[0], (int)guid.node[1], (int)guid.node[2],
+ (int)guid.node[3], (int)guid.node[4], (int)guid.node[5]);
+ return guid;
+}
+
/* ipmi_mc_print_guid - print-out given BMC GUID
*
* @param[in] intf - The IPMI interface to request GUID from
@@ -740,24 +761,11 @@ ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
printf("System GUID : ");
- guid = ipmi_parse_guid(guid_data, guid_mode);
- if (GUID_DUMP == guid.mode) {
- size_t i;
- for (i = 0; i < sizeof(guid_data); ++i) {
- printf("%02X", guid_data[i]);
- }
- printf("\n");
- return 0;
- }
-
- printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
- (int)guid.time_low,
- (int)guid.time_mid,
- (int)guid.time_hi_and_version,
- guid.clock_seq_and_rsvd,
- guid.node[0], guid.node[1], guid.node[2],
- guid.node[3], guid.node[4], guid.node[5]);
+ char buf[GUID_STR_MAXLEN + 1];
+ guid = ipmi_guid2str(buf, guid_data, guid_mode);
+ printf("%s\n", buf);
+ /* Print the GUID properties */
if (GUID_AUTO == guid_mode) {
/* ipmi_parse_guid() returns only valid modes in guid.ver */
printf("GUID Encoding : %s", guid_mode_str[guid.mode]);