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>
This commit is contained in:
Alexander Amelkin 2022-12-06 01:12:29 +03:00 committed by Alexander Amelkin
parent 1edb0e27e4
commit f033b5549e
4 changed files with 180 additions and 18 deletions

View File

@ -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;
@ -241,6 +244,43 @@ struct fru_multirec_dcload {
#pragma pack(0)
#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

View File

@ -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

View File

@ -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
}
} while (!(h->format & 0x80));
};
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 & FRU_RECORD_FORMAT_EOL_MASK));
lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off);

View File

@ -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]);