mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 10:37:22 +00:00
mc: guid: Add support for non-standard encodings
There are lots of BMC implementations that violate the IPMI specification in regard to GUID encoding and instead encode GUIDs according to either RFC4122 or SMBIOS specifications. This commit restores the default behavior of `mc guid` to SMBIOS-based decoding and adds options to allow for decoding according to IPMI or RFC4122 specifications. It also allows to simply dump the received GUID as is without any parsing. It is possible that in future versions `ipmitool` will change default behavior to 'ipmi' instead of 'smbios'. Partially resolves ipmitool/ipmitool#25 Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
This commit is contained in:
parent
b44ec2fb65
commit
f43a78bfc3
@ -2017,9 +2017,50 @@ The default will clear statistics on the first found LAN channel.
|
|||||||
|
|
||||||
Instructs the BMC to perform a warm or cold reset.
|
Instructs the BMC to perform a warm or cold reset.
|
||||||
.TP
|
.TP
|
||||||
\fIguid\fP
|
\fIguid\fP [\fBsmbios\fR|\fBrfc4122\fR|\fBipmi\fR|\fBdump\fR]
|
||||||
|
|
||||||
Display the Management Controller Globally Unique IDentifier.
|
Display the Management Controller Globally Unique IDentifier.
|
||||||
|
|
||||||
|
.RS
|
||||||
|
.TP
|
||||||
|
\fIsmbios\fP
|
||||||
|
.br
|
||||||
|
|
||||||
|
This is the default behavior for ipmitool for the sake of compatibility
|
||||||
|
with old versions and broken BMC implementations whose number is legion.
|
||||||
|
|
||||||
|
Decode GUID as if it was sent by BMC as prescribed by SMBIOS specification.
|
||||||
|
|
||||||
|
\fBNOTE:\fR This is a violation of IPMI specification, but many BMC implementations do
|
||||||
|
it this way. If your BMC's GUID is shown correctly using this option, you
|
||||||
|
may want to inform your BMC manufacturer that they have a bug.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fIrfc4122\fP or \fIrfc\fP
|
||||||
|
.br
|
||||||
|
|
||||||
|
Decode GUID as if it was sent by BMC as prescribed by RFC4122 specification.
|
||||||
|
|
||||||
|
\fBNOTE:\fR This is a violation of IPMI specification.
|
||||||
|
If your BMC's GUID is shown correctly using this option, you
|
||||||
|
may want to inform your BMC manufacturer that they have a bug.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fIipmi\fP
|
||||||
|
.br
|
||||||
|
|
||||||
|
Decode GUID according to IPMI specification. It MUST show the correct GUID.
|
||||||
|
If it doesn't, try other options above and inform your BMC manufacturer of the bug.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fIdump\fP
|
||||||
|
.br
|
||||||
|
|
||||||
|
Dump as hex the data received from BMC in response to Get Device GUID command.
|
||||||
|
No decoding or interpretation is performed. First received byte is dumped first.
|
||||||
|
|
||||||
|
.RE
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fIinfo\fP
|
\fIinfo\fP
|
||||||
.br
|
.br
|
||||||
|
@ -97,23 +97,58 @@ struct ipm_devid_rsp {
|
|||||||
|
|
||||||
#define IPM_DEV_ADTL_SUPPORT_BITS (8)
|
#define IPM_DEV_ADTL_SUPPORT_BITS (8)
|
||||||
|
|
||||||
/* Structure follow the IPMI V.2 Rev 1.0
|
/* There are lots of BMC implementations that don't follow the IPMI
|
||||||
* See Table 20-10 */
|
* specification for GUID encoding. Some send data encoded as in
|
||||||
|
* RFC4122, some follow SMBIOS specification. We support all users
|
||||||
|
* of those buggy implementations here */
|
||||||
|
typedef enum {
|
||||||
|
GUID_IPMI,
|
||||||
|
GUID_SMBIOS,
|
||||||
|
GUID_RFC4122,
|
||||||
|
GUID_DUMP
|
||||||
|
} ipmi_guid_mode_t;
|
||||||
|
|
||||||
|
#define GUID_NODE_SZ 6
|
||||||
|
|
||||||
|
/* The structure follows IPMI v2.0, rev 1.1
|
||||||
|
* See section 20.8 */
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
struct ipmi_guid_t {
|
struct ipmi_guid_t {
|
||||||
uint8_t node[6]; /* node */
|
uint8_t node[GUID_NODE_SZ]; /* Byte 0 is LSB */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint8_t clock_seq_low; /* clock sequence low field */
|
uint8_t clock_seq_low; /* clock sequence low field */
|
||||||
uint8_t clock_seq_hi_variant;/* clock sequence high field and variant */
|
uint8_t clock_seq_hi_and_rsvd;/* clock sequence high field */
|
||||||
};
|
};
|
||||||
uint16_t clock_seq_variant;
|
uint16_t clock_seq_and_rsvd;
|
||||||
};
|
};
|
||||||
uint16_t time_hi_and_version; /* timestamp high field and version number */
|
uint16_t time_hi_and_version; /* timestamp high field and version number */
|
||||||
uint16_t time_mid; /* timestamp middle field */
|
uint16_t time_mid; /* timestamp middle field */
|
||||||
uint32_t time_low; /* timestamp low field */
|
uint32_t time_low; /* timestamp low field */
|
||||||
|
} ATTRIBUTE_PACKING;
|
||||||
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
|
#pragma pack(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The structure follows RFC4122 (section 4.1.2)
|
||||||
|
* and SMBIOS v3.0.0 (section 7.2.1) */
|
||||||
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
|
#pragma pack(1)
|
||||||
|
#endif
|
||||||
|
struct rfc_guid_t {
|
||||||
|
uint32_t time_low; /* timestamp low field */
|
||||||
|
uint16_t time_mid; /* timestamp middle field */
|
||||||
|
uint16_t time_hi_and_version; /* timestamp high field and version number */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t clock_seq_hi_and_rsvd;/* clock sequence high field */
|
||||||
|
uint8_t clock_seq_low; /* clock sequence low field */
|
||||||
|
};
|
||||||
|
uint16_t clock_seq_and_rsvd;
|
||||||
|
};
|
||||||
|
uint8_t node[GUID_NODE_SZ]; /* Byte 0 is MSB */
|
||||||
} ATTRIBUTE_PACKING;
|
} ATTRIBUTE_PACKING;
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(0)
|
#pragma pack(0)
|
||||||
|
132
lib/ipmi_mc.c
132
lib/ipmi_mc.c
@ -38,6 +38,8 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <ipmitool/helper.h>
|
#include <ipmitool/helper.h>
|
||||||
#include <ipmitool/log.h>
|
#include <ipmitool/log.h>
|
||||||
#include <ipmitool/bswap.h>
|
#include <ipmitool/bswap.h>
|
||||||
@ -184,7 +186,7 @@ printf_mc_usage(void)
|
|||||||
struct bitfield_data * bf;
|
struct bitfield_data * bf;
|
||||||
lprintf(LOG_NOTICE, "MC Commands:");
|
lprintf(LOG_NOTICE, "MC Commands:");
|
||||||
lprintf(LOG_NOTICE, " reset <warm|cold>");
|
lprintf(LOG_NOTICE, " reset <warm|cold>");
|
||||||
lprintf(LOG_NOTICE, " guid");
|
lprintf(LOG_NOTICE, " guid [smbios|rfc4122|ipmi|dump]");
|
||||||
lprintf(LOG_NOTICE, " info");
|
lprintf(LOG_NOTICE, " info");
|
||||||
lprintf(LOG_NOTICE, " watchdog <get|reset|off>");
|
lprintf(LOG_NOTICE, " watchdog <get|reset|off>");
|
||||||
lprintf(LOG_NOTICE, " selftest");
|
lprintf(LOG_NOTICE, " selftest");
|
||||||
@ -521,54 +523,86 @@ _ipmi_mc_get_guid(struct ipmi_intf *intf, struct ipmi_guid_t *guid)
|
|||||||
|
|
||||||
/* ipmi_mc_print_guid - print-out given BMC GUID
|
/* ipmi_mc_print_guid - print-out given BMC GUID
|
||||||
*
|
*
|
||||||
* @guid - struct with GUID.
|
* @param[in] intf - The IPMI interface to request GUID from
|
||||||
|
* @param[in] guid_mode - GUID decoding mode
|
||||||
*
|
*
|
||||||
* returns 0
|
* @returns status code
|
||||||
|
* @retval 0 - Success
|
||||||
|
* @retval -1 - Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ipmi_mc_print_guid(struct ipmi_guid_t guid)
|
ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
|
||||||
{
|
{
|
||||||
char tbuf[40];
|
/* Field order is different for RFC4122/SMBIOS and for IPMI */
|
||||||
time_t s;
|
struct ipmi_guid_t ipmi_guid;
|
||||||
memset(tbuf, 0, 40);
|
struct rfc_guid_t *rfc_guid; /* Alias pointer */
|
||||||
|
|
||||||
|
uint8_t node[GUID_NODE_SZ]; /* MSB first */
|
||||||
|
/* These are host architecture specific */
|
||||||
|
uint16_t clock_seq_and_rsvd;
|
||||||
|
uint16_t time_hi_and_version;
|
||||||
|
uint16_t time_mid;
|
||||||
|
uint32_t time_low;
|
||||||
|
|
||||||
|
char tbuf[40] = { 0 };
|
||||||
struct tm *tm;
|
struct tm *tm;
|
||||||
|
|
||||||
printf("System GUID : %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
|
|
||||||
/* We're displaying GUID as hex integers. Thus we need them to be
|
|
||||||
* in host byte order before we display them. However, according to
|
|
||||||
* IPMI 2.0, all GUID fields are in LSB first (Little Endian)
|
|
||||||
* format. Hence the ipmiXtoh() calls:
|
|
||||||
*/
|
|
||||||
ipmi32toh(&guid.time_low),
|
|
||||||
ipmi16toh(&guid.time_mid),
|
|
||||||
ipmi16toh(&guid.time_hi_and_version),
|
|
||||||
ipmi16toh(&guid.clock_seq_variant),
|
|
||||||
/* The node part is shown as bytes, so no additional conversion */
|
|
||||||
guid.node[5], guid.node[4], guid.node[3],
|
|
||||||
guid.node[2], guid.node[1], guid.node[0]);
|
|
||||||
|
|
||||||
s = (time_t)ipmi32toh(&guid.time_low);
|
|
||||||
if(time_in_utc)
|
|
||||||
tm = gmtime(&s);
|
|
||||||
else
|
|
||||||
tm = localtime(&s);
|
|
||||||
strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", tm);
|
|
||||||
printf("Timestamp : %s\n", tbuf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ipmi_mc_get_guid - Gets and prints-out System GUID */
|
|
||||||
int
|
|
||||||
ipmi_mc_get_guid(struct ipmi_intf *intf)
|
|
||||||
{
|
|
||||||
struct ipmi_guid_t guid;
|
|
||||||
int rc;
|
int rc;
|
||||||
rc = _ipmi_mc_get_guid(intf, &guid);
|
|
||||||
|
rc = _ipmi_mc_get_guid(intf, &ipmi_guid);
|
||||||
if (eval_ccode(rc) != 0) {
|
if (eval_ccode(rc) != 0) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
rc = ipmi_mc_print_guid(guid);
|
|
||||||
return rc;
|
printf("System GUID : ");
|
||||||
|
if (GUID_DUMP == guid_mode) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < sizeof(ipmi_guid); ++i) {
|
||||||
|
printf("%02X", ((uint8_t *)&ipmi_guid)[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUID_IPMI == guid_mode) {
|
||||||
|
/* In IPMI all fields are little-endian (LSB first) */
|
||||||
|
memcpy(node,
|
||||||
|
array_byteswap(ipmi_guid.node, GUID_NODE_SZ),
|
||||||
|
GUID_NODE_SZ);
|
||||||
|
clock_seq_and_rsvd = ipmi16toh(&ipmi_guid.clock_seq_and_rsvd);
|
||||||
|
time_low = ipmi32toh(&ipmi_guid.time_low);
|
||||||
|
time_mid = ipmi16toh(&ipmi_guid.time_mid);
|
||||||
|
time_hi_and_version = ipmi16toh(&ipmi_guid.time_hi_and_version);
|
||||||
|
} else {
|
||||||
|
/* For RFC4122 all fields are in network byte order (MSB first) */
|
||||||
|
rfc_guid = (struct rfc_guid_t *)(&ipmi_guid);
|
||||||
|
memcpy(node,
|
||||||
|
rfc_guid->node,
|
||||||
|
GUID_NODE_SZ);
|
||||||
|
clock_seq_and_rsvd = ntohs(rfc_guid->clock_seq_and_rsvd);
|
||||||
|
if (GUID_RFC4122 == guid_mode) {
|
||||||
|
time_low = ntohl(rfc_guid->time_low);
|
||||||
|
time_mid = ntohs(rfc_guid->time_mid);
|
||||||
|
time_hi_and_version = ntohs(rfc_guid->time_hi_and_version);
|
||||||
|
} else {
|
||||||
|
/* For SMBIOS time fields are little-endian (as in IPMI) */
|
||||||
|
time_low = ipmi32toh(&rfc_guid->time_low);
|
||||||
|
time_mid = ipmi16toh(&rfc_guid->time_mid);
|
||||||
|
time_hi_and_version = ipmi16toh(&rfc_guid->time_hi_and_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
|
||||||
|
time_low, time_mid, time_hi_and_version,
|
||||||
|
clock_seq_and_rsvd,
|
||||||
|
node[0], node[1], node[2], node[3], node[4], node[5]);
|
||||||
|
|
||||||
|
if(time_in_utc)
|
||||||
|
tm = gmtime(&time_low);
|
||||||
|
else
|
||||||
|
tm = localtime(&time_low);
|
||||||
|
strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", tm);
|
||||||
|
printf("Timestamp : %s\n", tbuf);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ipmi_mc_get_selftest - returns and print selftest results
|
/* ipmi_mc_get_selftest - returns and print selftest results
|
||||||
@ -1102,7 +1136,23 @@ ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
rc = ipmi_mc_get_deviceid(intf);
|
rc = ipmi_mc_get_deviceid(intf);
|
||||||
}
|
}
|
||||||
else if (strncmp(argv[0], "guid", 4) == 0) {
|
else if (strncmp(argv[0], "guid", 4) == 0) {
|
||||||
rc = ipmi_mc_get_guid(intf);
|
/* Most implementations like AMI MegaRAC do it the SMBIOS way.
|
||||||
|
* This is the legacy behavior we don't want to break yet. */
|
||||||
|
ipmi_guid_mode_t guid_mode = GUID_SMBIOS;
|
||||||
|
|
||||||
|
/* Allow for 'rfc' and 'rfc4122' */
|
||||||
|
if (argc > 1) {
|
||||||
|
if (!strncmp(argv[1], "rfc", 3)) {
|
||||||
|
guid_mode = GUID_RFC4122;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[1], "ipmi")) {
|
||||||
|
guid_mode = GUID_IPMI;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[1], "dump")) {
|
||||||
|
guid_mode = GUID_DUMP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc = ipmi_mc_print_guid(intf, guid_mode);
|
||||||
}
|
}
|
||||||
else if (strncmp(argv[0], "getenables", 10) == 0) {
|
else if (strncmp(argv[0], "getenables", 10) == 0) {
|
||||||
rc = ipmi_mc_get_enables(intf);
|
rc = ipmi_mc_get_enables(intf);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user