mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
mc: guid: Implement encoding autodetection
With this commit the GUID encoding is now by default detected automatically based on the validity of the version field, and the timestamp (for time-based version 1 GUIDs). The version is considered valid if it is 1 through 5. The timestamp is considered valid if the year is past UNIX Epoch and before the current year. Resolves ipmitool/ipmitool#25 Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
This commit is contained in:
parent
0b6abe8cd9
commit
40d52b5fa1
@ -2023,11 +2023,35 @@ Display the Management Controller Globally Unique IDentifier.
|
|||||||
|
|
||||||
.RS
|
.RS
|
||||||
.TP
|
.TP
|
||||||
\fIsmbios\fP
|
\fIauto\fP
|
||||||
.br
|
.br
|
||||||
|
|
||||||
This is the default behavior for ipmitool for the sake of compatibility
|
This is the default behavior for
|
||||||
with old versions and broken BMC implementations whose number is legion.
|
.BR ipmitool (1).
|
||||||
|
|
||||||
|
Try to automatically detect the encoding based on the value of the
|
||||||
|
version field and (for version 1) the timestamp. The version is
|
||||||
|
considered valid if it is 1 through 5, and the timestamp is valid
|
||||||
|
if the year is past or equal to UNIX Epoch (1970) and is before or
|
||||||
|
equal to the current year.
|
||||||
|
|
||||||
|
If multiple encodings happen to have valid version fields, then
|
||||||
|
precedence takes the one with version 1 and a valid timestamp. If
|
||||||
|
neither one has that, then the precedence order is as follows:
|
||||||
|
\fIsmbios\fP, \fIipmi\fP, \fIrfc4122\fP.
|
||||||
|
|
||||||
|
If neither encoding yields a valid version field, then
|
||||||
|
.BR ipmitool (1)
|
||||||
|
defaults to \fIdump\fP mode.
|
||||||
|
|
||||||
|
If this option is in use, then
|
||||||
|
.BR ipmitool (1)
|
||||||
|
will also print out the detected encoding and warn
|
||||||
|
regarding IPMI specification violation if the encoding isn't \fIipmi\fP.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fIsmbios\fP
|
||||||
|
.br
|
||||||
|
|
||||||
Decode GUID as if it was sent by BMC as prescribed by SMBIOS specification.
|
Decode GUID as if it was sent by BMC as prescribed by SMBIOS specification.
|
||||||
|
|
||||||
@ -2035,6 +2059,13 @@ Decode GUID as if it was sent by BMC as prescribed by SMBIOS specification.
|
|||||||
it this way. If your BMC's GUID is shown correctly using this option, you
|
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.
|
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 and inform your BMC manufacturer of the bug.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fIrfc4122\fP or \fIrfc\fP
|
\fIrfc4122\fP or \fIrfc\fP
|
||||||
.br
|
.br
|
||||||
@ -2045,13 +2076,6 @@ Decode GUID as if it was sent by BMC as prescribed by RFC4122 specification.
|
|||||||
If your BMC's GUID is shown correctly using this option, you
|
If your BMC's GUID is shown correctly using this option, you
|
||||||
may want to inform your BMC manufacturer that they have a bug.
|
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
|
.TP
|
||||||
\fIdump\fP
|
\fIdump\fP
|
||||||
.br
|
.br
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
#ifndef IPMI_MC_H
|
#ifndef IPMI_MC_H
|
||||||
#define IPMI_MC_H
|
#define IPMI_MC_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <ipmitool/ipmi.h>
|
#include <ipmitool/ipmi.h>
|
||||||
#include <ipmitool/helper.h>
|
#include <ipmitool/helper.h>
|
||||||
#include <ipmitool/ipmi_strings.h>
|
#include <ipmitool/ipmi_strings.h>
|
||||||
@ -100,12 +102,28 @@ struct ipm_devid_rsp {
|
|||||||
/* There are lots of BMC implementations that don't follow the IPMI
|
/* There are lots of BMC implementations that don't follow the IPMI
|
||||||
* specification for GUID encoding. Some send data encoded as in
|
* specification for GUID encoding. Some send data encoded as in
|
||||||
* RFC4122, some follow SMBIOS specification. We support all users
|
* RFC4122, some follow SMBIOS specification. We support all users
|
||||||
* of those buggy implementations here */
|
* of those buggy implementations here.
|
||||||
|
*
|
||||||
|
* Most implementations like AMI MegaRAC do it the SMBIOS way.
|
||||||
|
* This is the legacy behavior we don't want to break yet.
|
||||||
|
* That's why the last real mode is GUID_SMBIOS. If automatic
|
||||||
|
* detection finds more than one possible candidate, and
|
||||||
|
* GUID_SMBIOS is one of them, then it will take precedence.
|
||||||
|
*
|
||||||
|
* For the same reason GUID_IPMI is right before GUID_SMBIOS.
|
||||||
|
* If both RFC4122 and IPMI encodings have a valid version
|
||||||
|
* field, then IPMI takes precedence.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
/* Real modes, in reverse precedence order */
|
||||||
|
GUID_RFC4122,
|
||||||
GUID_IPMI,
|
GUID_IPMI,
|
||||||
GUID_SMBIOS,
|
GUID_SMBIOS,
|
||||||
GUID_RFC4122,
|
GUID_REAL_MODES, /* Real mode count*/
|
||||||
GUID_DUMP
|
/* Pseudo modes start here */
|
||||||
|
GUID_AUTO = GUID_REAL_MODES, /* Automatically detect mode */
|
||||||
|
GUID_DUMP, /* Just dump the data */
|
||||||
|
GUID_TOTAL_MODES
|
||||||
} ipmi_guid_mode_t;
|
} ipmi_guid_mode_t;
|
||||||
|
|
||||||
#define GUID_NODE_SZ 6
|
#define GUID_NODE_SZ 6
|
||||||
@ -129,12 +147,17 @@ typedef enum {
|
|||||||
GUID_VERSION_COUNT /* The number of supported versions */
|
GUID_VERSION_COUNT /* The number of supported versions */
|
||||||
} guid_version_t;
|
} guid_version_t;
|
||||||
|
|
||||||
|
static inline bool is_guid_version_valid(guid_version_t ver)
|
||||||
|
{
|
||||||
|
return (ver > GUID_VERSION_UNKNOWN) && (ver <= GUID_VERSION_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
/* The structure follows IPMI v2.0, rev 1.1
|
/* The structure follows IPMI v2.0, rev 1.1
|
||||||
* See section 20.8 */
|
* See section 20.8 */
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
struct ipmi_guid_t {
|
typedef struct {
|
||||||
uint8_t node[GUID_NODE_SZ]; /* Byte 0 is LSB */
|
uint8_t node[GUID_NODE_SZ]; /* Byte 0 is LSB */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
@ -146,7 +169,7 @@ struct ipmi_guid_t {
|
|||||||
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;
|
} ATTRIBUTE_PACKING ipmi_guid_t;
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(0)
|
#pragma pack(0)
|
||||||
#endif
|
#endif
|
||||||
@ -156,7 +179,7 @@ struct ipmi_guid_t {
|
|||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
struct rfc_guid_t {
|
typedef struct {
|
||||||
uint32_t time_low; /* timestamp low field */
|
uint32_t time_low; /* timestamp low field */
|
||||||
uint16_t time_mid; /* timestamp middle field */
|
uint16_t time_mid; /* timestamp middle field */
|
||||||
uint16_t time_hi_and_version; /* timestamp high field and version number */
|
uint16_t time_hi_and_version; /* timestamp high field and version number */
|
||||||
@ -168,12 +191,28 @@ struct rfc_guid_t {
|
|||||||
uint16_t clock_seq_and_rsvd;
|
uint16_t clock_seq_and_rsvd;
|
||||||
};
|
};
|
||||||
uint8_t node[GUID_NODE_SZ]; /* Byte 0 is MSB */
|
uint8_t node[GUID_NODE_SZ]; /* Byte 0 is MSB */
|
||||||
} ATTRIBUTE_PACKING;
|
} ATTRIBUTE_PACKING rfc_guid_t;
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(0)
|
#pragma pack(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int _ipmi_mc_get_guid(struct ipmi_intf *, struct ipmi_guid_t *);
|
/* Parsed GUID structure */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t node[GUID_NODE_SZ]; /* MSB first */
|
||||||
|
/* These are architecture-specific for easy output with printf() */
|
||||||
|
uint16_t clock_seq_and_rsvd;
|
||||||
|
uint64_t time_hi_and_version;
|
||||||
|
uint64_t time_mid;
|
||||||
|
uint64_t time_low;
|
||||||
|
/* These are the parsed values */
|
||||||
|
time_t time;
|
||||||
|
ipmi_guid_mode_t mode;
|
||||||
|
guid_version_t ver; /* Version from time_hi_and_version, if valid */
|
||||||
|
} parsed_guid_t;
|
||||||
|
|
||||||
|
parsed_guid_t ipmi_parse_guid(void *guid, ipmi_guid_mode_t guid_mode);
|
||||||
|
|
||||||
|
int _ipmi_mc_get_guid(struct ipmi_intf *intf, ipmi_guid_t *guid);
|
||||||
|
|
||||||
#ifdef HAVE_PRAGMA_PACK
|
#ifdef HAVE_PRAGMA_PACK
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
314
lib/ipmi_mc.c
314
lib/ipmi_mc.c
@ -186,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 [smbios|rfc4122|ipmi|dump]");
|
lprintf(LOG_NOTICE, " guid [auto|smbios|ipmi|rfc4122|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");
|
||||||
@ -495,7 +495,7 @@ ipmi_mc_get_deviceid(struct ipmi_intf * intf)
|
|||||||
* returns - negative number means error, positive is a ccode.
|
* returns - negative number means error, positive is a ccode.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
_ipmi_mc_get_guid(struct ipmi_intf *intf, struct ipmi_guid_t *guid)
|
_ipmi_mc_get_guid(struct ipmi_intf *intf, ipmi_guid_t *guid)
|
||||||
{
|
{
|
||||||
struct ipmi_rs *rsp;
|
struct ipmi_rs *rsp;
|
||||||
struct ipmi_rq req;
|
struct ipmi_rq req;
|
||||||
@ -503,7 +503,7 @@ _ipmi_mc_get_guid(struct ipmi_intf *intf, struct ipmi_guid_t *guid)
|
|||||||
return (-3);
|
return (-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(guid, 0, sizeof(struct ipmi_guid_t));
|
memset(guid, 0, sizeof(ipmi_guid_t));
|
||||||
memset(&req, 0, sizeof(req));
|
memset(&req, 0, sizeof(req));
|
||||||
req.msg.netfn = IPMI_NETFN_APP;
|
req.msg.netfn = IPMI_NETFN_APP;
|
||||||
req.msg.cmd = BMC_GET_GUID;
|
req.msg.cmd = BMC_GET_GUID;
|
||||||
@ -514,13 +514,188 @@ _ipmi_mc_get_guid(struct ipmi_intf *intf, struct ipmi_guid_t *guid)
|
|||||||
} else if (rsp->ccode) {
|
} else if (rsp->ccode) {
|
||||||
return rsp->ccode;
|
return rsp->ccode;
|
||||||
} else if (rsp->data_len != 16
|
} else if (rsp->data_len != 16
|
||||||
|| rsp->data_len != sizeof(struct ipmi_guid_t)) {
|
|| rsp->data_len != sizeof(ipmi_guid_t)) {
|
||||||
return (-2);
|
return (-2);
|
||||||
}
|
}
|
||||||
memcpy(guid, &rsp->data[0], sizeof(struct ipmi_guid_t));
|
memcpy(guid, &rsp->data[0], sizeof(ipmi_guid_t));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A helper function to convert GUID time to time_t */
|
||||||
|
static time_t _guid_time(uint64_t t_low, uint64_t t_mid, uint64_t t_hi)
|
||||||
|
{
|
||||||
|
/* GUID time-stamp is a 60-bit value representing the
|
||||||
|
* count of 100ns intervals since 00:00:00.00, 15 Oct 1582 */
|
||||||
|
|
||||||
|
const uint64_t t100ns_in_sec = 10000000LL;
|
||||||
|
|
||||||
|
/* Seconds from 15 Oct 1582 to 1 Jan 1970 00:00:00 */
|
||||||
|
uint64_t epoch_since_gregorian = 12219292800;
|
||||||
|
|
||||||
|
/* 100ns intervals since 15 Oct 1582 00:00:00 */
|
||||||
|
uint64_t gregorian = (GUID_TIME_HI(t_hi) << 48)
|
||||||
|
| (t_mid << 32)
|
||||||
|
| t_low;
|
||||||
|
time_t unixtime; /* We need timestamp in seconds since UNIX epoch */
|
||||||
|
|
||||||
|
gregorian /= t100ns_in_sec; /* Convert to seconds */
|
||||||
|
unixtime = gregorian - epoch_since_gregorian;
|
||||||
|
|
||||||
|
return unixtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TM_YEAR_BASE 1900
|
||||||
|
#define EPOCH_YEAR 1970
|
||||||
|
static bool _is_time_valid(time_t t)
|
||||||
|
{
|
||||||
|
time_t t_now = time(NULL);
|
||||||
|
struct tm tm;
|
||||||
|
struct tm now;
|
||||||
|
|
||||||
|
gmtime_r(&t, &tm);
|
||||||
|
gmtime_r(&t_now, &now);
|
||||||
|
|
||||||
|
/* It's enought to check that the year fits in [Epoch .. now] interval */
|
||||||
|
|
||||||
|
if (tm.tm_year + TM_YEAR_BASE < EPOCH_YEAR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tm.tm_year > now.tm_year) {
|
||||||
|
/* GUID timestamp can't be in future */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ipmi_mc_parse_guid - print-out given BMC GUID
|
||||||
|
*
|
||||||
|
* The function parses the raw guid data according to the requested encoding
|
||||||
|
* mode. If GUID_AUTO mode is requested, then automatic detection of encoding
|
||||||
|
* is attempted using the version nibble of the time_hi_and_version field of
|
||||||
|
* each of the supported encodings.
|
||||||
|
*
|
||||||
|
* Considering the rather random nature of GUIDs, it may happen that the
|
||||||
|
* version nibble is valid for multiple encodings at the same time. That's why
|
||||||
|
* if the version is 1 (time-based), the function will also check validity of
|
||||||
|
* the time stamp. If a valid time stamp is found for a given mode, the mode is
|
||||||
|
* considered detected and no further checks are performed. Otherwise other
|
||||||
|
* encodings are probed the same way. If in neither encoding the valid version
|
||||||
|
* nibble happened to indicate time-based version or no valid time-stamp has
|
||||||
|
* been found, then the last probed encoding with valid version nibble is
|
||||||
|
* considered detected. If none of the probed encodings indicated a valid
|
||||||
|
* version nibble, then fall back to GUID_DUMP
|
||||||
|
*
|
||||||
|
* @param[in] guid - The original GUID data as received from BMC
|
||||||
|
* @param[in] mode - The requested mode/encoding
|
||||||
|
*
|
||||||
|
* @returns parsed GUID
|
||||||
|
*/
|
||||||
|
parsed_guid_t ipmi_parse_guid(void *guid, ipmi_guid_mode_t guid_mode)
|
||||||
|
{
|
||||||
|
ipmi_guid_mode_t i;
|
||||||
|
ipmi_guid_t *ipmi_guid = guid;
|
||||||
|
rfc_guid_t *rfc_guid = guid;
|
||||||
|
parsed_guid_t parsed_guid = { 0 };
|
||||||
|
uint32_t t_low[GUID_REAL_MODES];
|
||||||
|
uint16_t t_mid[GUID_REAL_MODES];
|
||||||
|
uint16_t t_hi[GUID_REAL_MODES];
|
||||||
|
uint16_t clk[GUID_REAL_MODES];
|
||||||
|
time_t seconds[GUID_REAL_MODES];
|
||||||
|
bool detect = false;
|
||||||
|
|
||||||
|
/* Unless another mode is detected, default to dumping */
|
||||||
|
if (GUID_AUTO == guid_mode) {
|
||||||
|
detect = true;
|
||||||
|
guid_mode = GUID_DUMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to convert time using all possible methods to use
|
||||||
|
* the result later if GUID_AUTO is requested */
|
||||||
|
|
||||||
|
/* For IPMI all fields are little-endian (LSB first) */
|
||||||
|
t_hi[GUID_IPMI] = ipmi16toh(&ipmi_guid->time_hi_and_version);
|
||||||
|
t_mid[GUID_IPMI] = ipmi16toh(&ipmi_guid->time_mid);
|
||||||
|
t_low[GUID_IPMI] = ipmi32toh(&ipmi_guid->time_low);
|
||||||
|
clk[GUID_IPMI] = ipmi16toh(&ipmi_guid->clock_seq_and_rsvd);
|
||||||
|
|
||||||
|
/* For RFC4122 all fields are in network byte order (MSB first) */
|
||||||
|
t_hi[GUID_RFC4122] = ntohs(rfc_guid->time_hi_and_version);
|
||||||
|
t_mid[GUID_RFC4122] = ntohs(rfc_guid->time_mid);
|
||||||
|
t_low[GUID_RFC4122] = ntohl(rfc_guid->time_low);
|
||||||
|
clk[GUID_RFC4122] = ntohs(rfc_guid->clock_seq_and_rsvd);
|
||||||
|
|
||||||
|
/* For SMBIOS time fields are little-endian (as in IPMI), the rest is
|
||||||
|
* in network order (as in RFC4122) */
|
||||||
|
t_hi[GUID_SMBIOS] = ipmi16toh(&rfc_guid->time_hi_and_version);
|
||||||
|
t_mid[GUID_SMBIOS] = ipmi16toh(&rfc_guid->time_mid);
|
||||||
|
t_low[GUID_SMBIOS] = ipmi32toh(&rfc_guid->time_low);
|
||||||
|
clk[GUID_SMBIOS] = ntohs(rfc_guid->clock_seq_and_rsvd);
|
||||||
|
|
||||||
|
/* Using 0 here to allow for reordering of modes in ipmi_guid_mode_t */
|
||||||
|
for (i = 0; i < GUID_REAL_MODES; ++i) {
|
||||||
|
seconds[i] = _guid_time(t_low[i], t_mid[i], t_hi[i]);
|
||||||
|
|
||||||
|
/* If autodetection was initially requested and mode
|
||||||
|
* hasn't been detected yet */
|
||||||
|
if (detect) {
|
||||||
|
guid_version_t ver = GUID_VERSION(t_hi[i]);
|
||||||
|
if (is_guid_version_valid(ver)) {
|
||||||
|
guid_mode = i;
|
||||||
|
if (GUID_VERSION_TIME == ver && _is_time_valid(seconds[i])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guid_mode >= GUID_REAL_MODES) {
|
||||||
|
guid_mode = GUID_DUMP;
|
||||||
|
/* The endianness and field order are irrelevant for dump mode */
|
||||||
|
memcpy(&parsed_guid, guid, sizeof(ipmi_guid_t));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return only a valid version in the parsed version field.
|
||||||
|
* If one needs the raw value, they still may use
|
||||||
|
* GUID_VERSION(parsed_guid.time_hi_and_version)
|
||||||
|
*/
|
||||||
|
parsed_guid.ver = GUID_VERSION(t_hi[guid_mode]);
|
||||||
|
if (parsed_guid.ver > GUID_VERSION_MAX) {
|
||||||
|
parsed_guid.ver = GUID_VERSION_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUID_VERSION_TIME == parsed_guid.ver) {
|
||||||
|
parsed_guid.time = seconds[guid_mode];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUID_IPMI == guid_mode) {
|
||||||
|
/*
|
||||||
|
* In IPMI all fields are little-endian (LSB first)
|
||||||
|
* That is, first byte last. Hence, swap before copying.
|
||||||
|
*/
|
||||||
|
memcpy(parsed_guid.node,
|
||||||
|
array_byteswap(ipmi_guid->node, GUID_NODE_SZ),
|
||||||
|
GUID_NODE_SZ);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* For RFC4122 and SMBIOS the node field is in network byte order.
|
||||||
|
* That is first byte first. Hence, copy as is.
|
||||||
|
*/
|
||||||
|
memcpy(parsed_guid.node, rfc_guid->node, GUID_NODE_SZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed_guid.time_low = t_low[guid_mode];
|
||||||
|
parsed_guid.time_mid = t_mid[guid_mode];
|
||||||
|
parsed_guid.time_hi_and_version = t_hi[guid_mode];
|
||||||
|
parsed_guid.clock_seq_and_rsvd = clk[guid_mode];
|
||||||
|
|
||||||
|
out:
|
||||||
|
parsed_guid.mode = guid_mode;
|
||||||
|
return parsed_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
|
||||||
@ -533,18 +708,12 @@ _ipmi_mc_get_guid(struct ipmi_intf *intf, struct ipmi_guid_t *guid)
|
|||||||
static int
|
static int
|
||||||
ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
|
ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
|
||||||
{
|
{
|
||||||
/* Field order is different for RFC4122/SMBIOS and for IPMI */
|
/* Allocate a byte array for ease of use in dump mode */
|
||||||
struct ipmi_guid_t ipmi_guid;
|
uint8_t guid_data[sizeof(ipmi_guid_t)];
|
||||||
struct rfc_guid_t *rfc_guid; /* Alias pointer */
|
|
||||||
|
|
||||||
uint8_t node[GUID_NODE_SZ]; /* MSB first */
|
|
||||||
/* These are host architecture specific */
|
/* These are host architecture specific */
|
||||||
uint16_t clock_seq_and_rsvd;
|
parsed_guid_t guid;
|
||||||
uint64_t time_hi_and_version;
|
|
||||||
uint64_t time_mid;
|
|
||||||
uint64_t time_low;
|
|
||||||
|
|
||||||
guid_version_t guid_ver;
|
|
||||||
const char *guid_ver_str[GUID_VERSION_COUNT] = {
|
const char *guid_ver_str[GUID_VERSION_COUNT] = {
|
||||||
[GUID_VERSION_UNKNOWN] = "Unknown/unsupported",
|
[GUID_VERSION_UNKNOWN] = "Unknown/unsupported",
|
||||||
[GUID_VERSION_TIME] = "Time-based",
|
[GUID_VERSION_TIME] = "Time-based",
|
||||||
@ -554,95 +723,70 @@ ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
|
|||||||
[GUID_VERSION_SHA1] = "Name-based using SHA-1"
|
[GUID_VERSION_SHA1] = "Name-based using SHA-1"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *guid_mode_str[GUID_TOTAL_MODES] = {
|
||||||
|
[GUID_IPMI] = "IPMI",
|
||||||
|
[GUID_RFC4122] = "RFC4122",
|
||||||
|
[GUID_SMBIOS] = "SMBIOS",
|
||||||
|
[GUID_AUTO] = "Automatic (if you see this, report a bug)",
|
||||||
|
[GUID_DUMP] = "Unknown (data dumped)"
|
||||||
|
};
|
||||||
|
|
||||||
char tbuf[40] = { 0 };
|
char tbuf[40] = { 0 };
|
||||||
struct tm *tm;
|
struct tm *tm;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = _ipmi_mc_get_guid(intf, &ipmi_guid);
|
rc = _ipmi_mc_get_guid(intf, (ipmi_guid_t *)guid_data);
|
||||||
if (eval_ccode(rc) != 0) {
|
if (eval_ccode(rc) != 0) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("System GUID : ");
|
printf("System GUID : ");
|
||||||
if (GUID_DUMP == guid_mode) {
|
|
||||||
|
guid = ipmi_parse_guid(guid_data, guid_mode);
|
||||||
|
if (GUID_DUMP == guid.mode) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < sizeof(ipmi_guid); ++i) {
|
for (i = 0; i < sizeof(guid_data); ++i) {
|
||||||
printf("%02X", ((uint8_t *)&ipmi_guid)[i]);
|
printf("%02X", guid_data[i]);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
return 0;
|
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",
|
printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
|
||||||
(int)time_low, (int)time_mid, (int)time_hi_and_version,
|
(int)guid.time_low,
|
||||||
clock_seq_and_rsvd,
|
(int)guid.time_mid,
|
||||||
node[0], node[1], node[2], node[3], node[4], node[5]);
|
(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]);
|
||||||
|
|
||||||
guid_ver = GUID_VERSION(time_hi_and_version);
|
if (GUID_AUTO == guid_mode) {
|
||||||
|
/* ipmi_parse_guid() returns only valid modes in guid.ver */
|
||||||
if (guid_ver > GUID_VERSION_MAX) {
|
printf("GUID Encoding : %s", guid_mode_str[guid.mode]);
|
||||||
/* Reset any unsupported value fto UNKNOWN */
|
if (GUID_IPMI != guid.mode) {
|
||||||
guid_ver = GUID_VERSION_UNKNOWN;
|
printf(" (WARNING: IPMI Specification violation!)");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("GUID Version : %s", guid_ver_str[guid_ver]);
|
printf("GUID Version : %s", guid_ver_str[guid.ver]);
|
||||||
if (GUID_VERSION_UNKNOWN == guid_ver)
|
|
||||||
printf(" (%d)", GUID_VERSION((int)time_hi_and_version));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
if (GUID_VERSION_TIME == guid_ver) {
|
|
||||||
/* GUID time-stamp is a 60-bit value representing the
|
|
||||||
* count of 100ns intervals since 00:00:00.00, 15 Oct 1582 */
|
|
||||||
|
|
||||||
const uint64_t t100ns_in_sec = 10000000LL;
|
|
||||||
|
|
||||||
/* Seconds from 15 Oct 1582 to 1 Jan 1970 00:00:00 */
|
|
||||||
uint64_t epoch_since_gregorian = 12219292800;
|
|
||||||
|
|
||||||
/* 100ns intervals since 15 Oct 1582 00:00:00 */
|
|
||||||
uint64_t gregorian = (GUID_TIME_HI(time_hi_and_version) << 48)
|
|
||||||
| (time_mid << 32)
|
|
||||||
| time_low;
|
|
||||||
time_t unixtime; /* We need timestamp in seconds since UNIX epoch */
|
|
||||||
|
|
||||||
gregorian /= t100ns_in_sec; /* Convert to seconds */
|
|
||||||
unixtime = gregorian - epoch_since_gregorian;
|
|
||||||
|
|
||||||
|
switch (guid.ver) {
|
||||||
|
case GUID_VERSION_UNKNOWN:
|
||||||
|
printf(" (%d)\n", GUID_VERSION((int)guid.time_hi_and_version));
|
||||||
|
break;
|
||||||
|
case GUID_VERSION_TIME:
|
||||||
if(time_in_utc)
|
if(time_in_utc)
|
||||||
tm = gmtime(&unixtime);
|
tm = gmtime(&guid.time);
|
||||||
else
|
else
|
||||||
tm = localtime(&unixtime);
|
tm = localtime(&guid.time);
|
||||||
strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", tm);
|
strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", tm);
|
||||||
printf("Timestamp : %s\n", tbuf);
|
printf("\nTimestamp : %s\n", tbuf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,18 +1321,22 @@ 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) {
|
||||||
/* Most implementations like AMI MegaRAC do it the SMBIOS way.
|
ipmi_guid_mode_t guid_mode = GUID_AUTO;
|
||||||
* 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' */
|
/* Allow for 'rfc' and 'rfc4122' */
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
if (!strncmp(argv[1], "rfc", 3)) {
|
if (!strncmp(argv[1], "rfc", 3)) {
|
||||||
guid_mode = GUID_RFC4122;
|
guid_mode = GUID_RFC4122;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[1], "smbios")) {
|
||||||
|
guid_mode = GUID_SMBIOS;
|
||||||
|
}
|
||||||
else if (!strcmp(argv[1], "ipmi")) {
|
else if (!strcmp(argv[1], "ipmi")) {
|
||||||
guid_mode = GUID_IPMI;
|
guid_mode = GUID_IPMI;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[1], "auto")) {
|
||||||
|
guid_mode = GUID_AUTO;
|
||||||
|
}
|
||||||
else if (!strcmp(argv[1], "dump")) {
|
else if (!strcmp(argv[1], "dump")) {
|
||||||
guid_mode = GUID_DUMP;
|
guid_mode = GUID_DUMP;
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1143,7 @@ ipmi_pef2_get_info(struct ipmi_intf *intf)
|
|||||||
{
|
{
|
||||||
struct pef_capabilities pcap;
|
struct pef_capabilities pcap;
|
||||||
struct pef_cfgparm_system_guid psys_guid;
|
struct pef_cfgparm_system_guid psys_guid;
|
||||||
struct ipmi_guid_t guid;
|
ipmi_guid_t guid;
|
||||||
int rc;
|
int rc;
|
||||||
uint8_t *guid_ptr = NULL;
|
uint8_t *guid_ptr = NULL;
|
||||||
uint8_t policy_table_size;
|
uint8_t policy_table_size;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user