mc: guid: Fix timestamp decoding

Before this commit the 'Timestamp' line was always printed
for all versions of GUID, even for non-time-based ones.

Plus, only the time_low field was used, and it was used as if
it contained seconds since UNIX Epoch, which it didn't. In fact
this field along with other time_* fields constitute a single
60-bit value representing the count of 100ns intervals since
adoption of Gregorial calendar (00:00:00.00 15 Oct 1582).

For non-time-based versions of GUID, the time_* fields do
not represent any time at all.

So, after this commit, the timestamp will be properly decoded
for time-based GUID version 1 only. For other versions the
'Timestamp' line will not be displayed. A line showing the
GUID version will be added to the output.

Partially resolves ipmitool/ipmitool#25

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
This commit is contained in:
Alexander Amelkin 2018-08-01 23:03:55 +03:00
parent f43a78bfc3
commit 0b6abe8cd9
No known key found for this signature in database
GPG Key ID: E893587B5B74178D
2 changed files with 70 additions and 10 deletions

View File

@ -110,6 +110,25 @@ typedef enum {
#define GUID_NODE_SZ 6
#define GUID_VER_MASK 0x0F
#define GUID_VER_SHIFT 12
#define GUID_VERSION(t_hi) (((t_hi) >> GUID_VER_SHIFT) & GUID_VER_MASK)
#define GUID_TIME_HI(t_hi) ((t_hi) & ~(GUID_VER_MASK << GUID_VER_SHIFT))
typedef enum {
GUID_VERSION_UNKNOWN = 0, /* Not valid according to any specification */
/* The following are according to IPMI/SMBIOS/RFC4122 */
GUID_VERSION_TIME, /* Time-based, recommended for IPMI */
GUID_VERSION_DCE, /* DCE Security with POSIX UIDs, not for IPMI */
GUID_VERSION_MD5, /* Name-based, using MD5 */
GUID_VERSION_RND, /* Randomly generated */
GUID_VERSION_SHA1, /* Name-based, using SHA-1 */
GUID_VERSION_MAX = GUID_VERSION_SHA1, /* The maximum supported version */
GUID_VERSION_COUNT /* The number of supported versions */
} guid_version_t;
/* The structure follows IPMI v2.0, rev 1.1
* See section 20.8 */
#ifdef HAVE_PRAGMA_PACK

View File

@ -540,9 +540,19 @@ ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
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;
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] = {
[GUID_VERSION_UNKNOWN] = "Unknown/unsupported",
[GUID_VERSION_TIME] = "Time-based",
[GUID_VERSION_DCE] = "DCE Security with POSIX UIDs (not for IPMI)",
[GUID_VERSION_MD5] = "Name-based using MD5",
[GUID_VERSION_RND] = "Random or pseudo-random",
[GUID_VERSION_SHA1] = "Name-based using SHA-1"
};
char tbuf[40] = { 0 };
struct tm *tm;
@ -592,16 +602,47 @@ ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
}
printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
time_low, time_mid, time_hi_and_version,
(int)time_low, (int)time_mid, (int)time_hi_and_version,
clock_seq_and_rsvd,
node[0], node[1], node[2], node[3], node[4], node[5]);
guid_ver = GUID_VERSION(time_hi_and_version);
if (guid_ver > GUID_VERSION_MAX) {
/* Reset any unsupported value fto UNKNOWN */
guid_ver = GUID_VERSION_UNKNOWN;
}
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;
if(time_in_utc)
tm = gmtime(&time_low);
tm = gmtime(&unixtime);
else
tm = localtime(&time_low);
tm = localtime(&unixtime);
strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", tm);
printf("Timestamp : %s\n", tbuf);
}
return 0;
}