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
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
|
/* See Table 16-1 of "IPMI FRU Information Storage Specification" */
|
||||||
struct fru_multirec_header {
|
struct fru_multirec_header {
|
||||||
#define FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION 0x00
|
#define FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION 0x00
|
||||||
#define FRU_RECORD_TYPE_DC_OUTPUT 0x01
|
#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_EXTENDED_COMPATIBILITY 0x05
|
||||||
#define FRU_RECORD_TYPE_OEM_EXTENSION 0xc0
|
#define FRU_RECORD_TYPE_OEM_EXTENSION 0xc0
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
#define FRU_RECORD_FORMAT_EOL_MASK 0x80
|
||||||
|
#define FRU_RECORD_FORMAT_VER_MASK 0x0F
|
||||||
uint8_t format;
|
uint8_t format;
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
uint8_t record_checksum;
|
uint8_t record_checksum;
|
||||||
@ -241,6 +244,43 @@ struct fru_multirec_dcload {
|
|||||||
#pragma pack(0)
|
#pragma pack(0)
|
||||||
#endif
|
#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
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
|
@ -211,6 +211,21 @@ typedef struct {
|
|||||||
|
|
||||||
parsed_guid_t ipmi_parse_guid(void *guid, ipmi_guid_mode_t guid_mode);
|
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);
|
int _ipmi_mc_get_guid(struct ipmi_intf *intf, ipmi_guid_t *guid);
|
||||||
|
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
|
101
lib/ipmi_fru.c
101
lib/ipmi_fru.c
@ -42,6 +42,7 @@
|
|||||||
#include <ipmitool/ipmi_time.h>
|
#include <ipmitool/ipmi_time.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -1283,6 +1284,26 @@ fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru,
|
|||||||
free_n(&fru_data);
|
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
|
/* fru_area_print_multirec - Print FRU Multi Record Area
|
||||||
*
|
*
|
||||||
* @intf: ipmi interface
|
* @intf: ipmi interface
|
||||||
@ -1467,8 +1488,86 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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);
|
lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off);
|
||||||
|
|
||||||
|
@ -696,6 +696,27 @@ out:
|
|||||||
return parsed_guid;
|
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
|
/* ipmi_mc_print_guid - print-out given BMC GUID
|
||||||
*
|
*
|
||||||
* @param[in] intf - The IPMI interface to request GUID from
|
* @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 : ");
|
printf("System GUID : ");
|
||||||
|
|
||||||
guid = ipmi_parse_guid(guid_data, guid_mode);
|
char buf[GUID_STR_MAXLEN + 1];
|
||||||
if (GUID_DUMP == guid.mode) {
|
guid = ipmi_guid2str(buf, guid_data, guid_mode);
|
||||||
size_t i;
|
printf("%s\n", buf);
|
||||||
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]);
|
|
||||||
|
|
||||||
|
/* Print the GUID properties */
|
||||||
if (GUID_AUTO == guid_mode) {
|
if (GUID_AUTO == guid_mode) {
|
||||||
/* ipmi_parse_guid() returns only valid modes in guid.ver */
|
/* ipmi_parse_guid() returns only valid modes in guid.ver */
|
||||||
printf("GUID Encoding : %s", guid_mode_str[guid.mode]);
|
printf("GUID Encoding : %s", guid_mode_str[guid.mode]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user