diff --git a/include/ipmitool/ipmi_fru.h b/include/ipmitool/ipmi_fru.h index 4d4d6c6..f301b09 100644 --- a/include/ipmitool/ipmi_fru.h +++ b/include/ipmitool/ipmi_fru.h @@ -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 diff --git a/include/ipmitool/ipmi_mc.h b/include/ipmitool/ipmi_mc.h index 65cba84..fd8c69a 100644 --- a/include/ipmitool/ipmi_mc.h +++ b/include/ipmitool/ipmi_mc.h @@ -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 diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c index 3d1d8a1..2d8daaf 100644 --- a/lib/ipmi_fru.c +++ b/lib/ipmi_fru.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -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); diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c index a594347..07978f7 100644 --- a/lib/ipmi_mc.c +++ b/lib/ipmi_mc.c @@ -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]);