mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
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:
parent
1edb0e27e4
commit
f033b5549e
@ -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
|
||||
|
@ -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
|
||||
|
101
lib/ipmi_fru.c
101
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);
|
||||
|
||||
|
@ -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]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user