dmidecode-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dmidecode] [PATCH v3] update dmidecode to parse Modern Management Contr


From: Neil Horman
Subject: [dmidecode] [PATCH v3] update dmidecode to parse Modern Management Controller blocks
Date: Tue, 7 Aug 2018 14:51:08 -0400

Starting with version 0x300 the SMBIOS specification defined in more
detail the contents of the management controller type.  DMTF further
reserved values to define the Redfish host interface specification.
Update dmidecode to properly parse and present that information

Signed-off-by: Neil Horman <address@hidden>
CC: address@hidden
CC: address@hidden
CC: address@hidden
CC: address@hidden

---
Change Notes:
V1->V2) Updated string formatting to print matching number of bytes
        for unsigned shorts (address@hidden)

        Adjusted string format for bDescriptor (address@hidden)

        Prefaced PCI id's with 0x (address@hidden)
V2->V3) Updated word and dword accesses to do appropriate endian
        conversion

        Updated Interface type and protocol type lists to reflect
        overall SMBIOS spec rather than just RedFish host spec, and stay
        more compatible with pre version 3 SMBIOS layouts

        Adjusted IFC_PROTO_RECORD_BASE to be 6 rather than 7, as this is
        in keeping with the spec, and is validated against the overall
        type 42 record length in his dmidecode dump.  I'm convinced that
        the layout of the system I'm testing on has an extra byte
        inserted between the protocol record count and the start of the
        protocol records.
---
 dmidecode.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 358 insertions(+), 16 deletions(-)

diff --git a/dmidecode.c b/dmidecode.c
index 76faed9..fc6ead6 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -56,6 +56,8 @@
  *  - "PC Client Platform TPM Profile (PTP) Specification"
  *    Family "2.0", Level 00, Revision 00.43, January 26, 2015
  *    
https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/
+ *  - "RedFish Host Interface Specification"
+ *    https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf
  */
 
 #include <stdio.h>
@@ -63,6 +65,7 @@
 #include <strings.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #ifdef __FreeBSD__
 #include <errno.h>
@@ -3447,6 +3450,341 @@ static void dmi_tpm_characteristics(u64 code, const 
char *prefix)
                                prefix, characteristics[i - 2]);
 }
 
+/*
+ * Type 42 data offsets
+ */
+
+/*
+ * Top Level Offsets
+ */
+#define IFC_TYPE 4
+#define IFC_SDATA_LEN 5
+#define IFC_PROTO_RECORD_BASE 6
+
+/*
+ * Interface specific data offsets
+ */
+#define IFC_DEVICE_TYPE 6
+
+/*
+ * USB Interface descriptor offsets
+ */
+#define USB_DESCRIPTOR 7
+#define USB_VENDOR 0
+#define USB_PRODUCT 2
+#define USB_SERIAL_LENGTH 4
+#define USB_SERIAL_DESCRIPTOR 5
+
+/*
+ * PCI Interface descriptor offsets
+ */
+#define PCI_DESCRIPTOR 7
+#define PCI_VENDOR 0
+#define PCI_DEVICE 2
+#define PCI_SUBVENDOR 4
+#define PCI_SUBDEVICE 6
+
+/*
+ * OEM Interface descriptor offsets
+ */
+#define OEM_DESCRIPTOR 7
+#define OEM_IANA 0
+
+/*
+ * Protocol Records Offsets
+ */
+#define IFC_PROTO_COUNT 0
+
+/*
+ * Pre Protocol Record Offsets
+ */
+#define PROTO_REC_ID 0
+#define PROTO_REC_LEN 1
+#define PROTO_REC_DATA 2
+
+/*
+ * Record data offsets
+ */
+#define REC_UUID 0
+#define REC_HOST_IP_ASGN_TYPE 16
+#define REC_HOST_IP_ADDR_FMT 17
+#define REC_HOST_ADDR 18
+#define REC_HOST_MASK 34
+#define REC_RFSH_DISC_TYPE 50
+#define REC_RFSH_ADDR_FMT 51
+#define REC_RFSH_ADDR 52
+#define REC_RFSH_MASK 68
+#define REC_RFSH_PORT 84
+#define REC_RFSH_VLAN 86
+#define REC_RFSH_HOST_LEN 90
+#define REC_RFSH_HOSTNAME 91
+
+/*
+ * TYPE 42 Data Field Values
+ */
+
+/*
+ * Top level values
+ */
+#define MCH_MCTP_HOST_IFC_MIN 0x0
+#define MCH_MCTP_HOST_IFC_MAX 0x3
+#define MCH_NET_HOST_IFC 0x40
+#define MCH_NET_OEM_IFC 0xF0
+
+/*
+ * Interface specific data values
+ */
+#define IFC_DEVICE_UNKNOWN 0x0
+#define IFC_DEVICE_USB 0x2
+#define IFC_DEVICE_PCI 0x3
+#define IFC_DEVICE_OEM 0x4 /* stand in map for IFC_DEVICE_OEM_MIN/MAX */
+#define IFC_DEVICE_OEM_MIN 0x80
+#define IFC_DEVICE_OEM_MAX 0xFF
+
+/*
+ * Protocol record data values
+ */
+#define PROTO_RESERVED 0x0
+#define PROTO_IPMI 0x2
+#define PROTO_MCTP 0x3
+#define PROTO_REDFISH_OVER_IP 0x4
+#define PROTO_OEM_MAP 0x5
+#define PROTO_UNKNOWN 0x6
+#define PROTO_OEM 0xF0
+
+/*
+ * Protocol record data values
+ */
+#define IP_UNKNOWN 0
+#define IP_STATIC 0x1
+#define IP_DHCP 0x2
+#define IP_AUTOCONF 0x3
+#define IP_HOSTSEL 0x4
+
+#define ADDR_UNKNOWN 0
+#define ADDR_IPV4 0x1
+#define ADDR_IPV6 0x2
+
+static void decode_management_controller_structure(const struct dmi_header *h, 
const char *prefix)
+{
+       u8 *data = h->data;
+       u8 type = data[IFC_TYPE];
+       u8 len = data[IFC_SDATA_LEN];
+       u8 count;
+       const char *devname[] = {
+               "Unknown",
+               "Unknown",
+               "USB",
+               "PCI[e]",
+               "OEM",
+       };
+
+       if (h->length < 0xB) {
+               printf("%s Invalid structure\n", prefix);
+               return;
+       }
+
+       printf("%sHost Interface Type: ", prefix);
+       if (type <= MCH_MCTP_HOST_IFC_MAX)
+               printf("MCTP\n");
+       else if (type == MCH_NET_HOST_IFC)
+               printf("Network\n");
+       else if (type == MCH_NET_OEM_IFC)
+               printf("OEM\n");
+       else
+               printf("Unknown\n");
+
+
+       if (len != 0) {
+               type = data[IFC_DEVICE_TYPE];
+               if (type >= IFC_DEVICE_OEM_MIN)
+                       type = IFC_DEVICE_OEM;
+
+               printf("%sDevice Type: %s\n", prefix, devname[type]);
+               if (type == IFC_DEVICE_USB) {
+                       /* USB */
+                       u8 *usbdata = &data[USB_DESCRIPTOR];
+                       printf("%s\tidVendor: 0x%04x\n", prefix, 
WORD(&usbdata[USB_VENDOR]));
+                       printf("%s\tidProduct: 0x%04x\n", prefix, 
WORD(&usbdata[USB_PRODUCT]));
+                       printf("%s\tSerialNumber:\n", prefix);
+                       printf("%s\t\tbDescriptor: 0x%02x\n", prefix, 
usbdata[USB_SERIAL_DESCRIPTOR]);
+                       /* Note bString is not printable here, so skip it */
+               } else if (type == IFC_DEVICE_PCI) {
+                       /* PCI */
+                       u8 *pcidata = &data[PCI_DESCRIPTOR];
+                       printf("%s\tVendorID: 0x%04x\n", prefix, 
WORD(&pcidata[PCI_VENDOR]));
+                       printf("%s\tDeviceID: 0x%04x\n", prefix, 
WORD(&pcidata[PCI_DEVICE]));
+                       printf("%s\tSubVendorID: 0x%04x\n", prefix, 
WORD(&pcidata[PCI_SUBVENDOR]));
+                       printf("%s\tSubDeviceID: 0x%04x\n", prefix, 
WORD(&pcidata[PCI_SUBDEVICE]));
+               } else if (type == IFC_DEVICE_OEM) {
+                       u32 *oemdata = (u32 *)&data[OEM_DESCRIPTOR];
+                       printf("%s\t Vendor ID: 0x%08x\n", prefix, 
DWORD(&oemdata[OEM_IANA]));
+               }
+               /* Don't mess with unknown types for now */
+       }
+
+       /*
+        * Move to the Protocol Count Area from Table 1
+        * Data[6] points to the start of the interface specific
+        * data, and Data[5] is the length of that region
+        */
+       data = &data[IFC_PROTO_RECORD_BASE+data[5]];
+
+       /* Get the protocol records count */
+       count = (u8)data[IFC_PROTO_COUNT];
+       if (count) {
+               int i, j, k;
+               u8 rid;
+               u8 rlen;
+               u8 *rec = &data[1]; /*first record starts after count value */
+               u8 *rdata;
+               u8 buf[64];
+               u8 uuid[37];
+               u8 assignval;
+               u8 addrtype;
+               u8 hlen;
+               char hname[257];
+
+               const char *protocoltypes[] = {
+                       "Reserved",
+                       "Reserved",
+                       "IPMI",
+                       "MCTP",
+                       "Redfish over IP",
+                       "OEM",
+                       "Unknown",
+               };
+
+               const char *assigntype[] = {
+                       "Unknown",
+                       "Static",
+                       "DHCP",
+                       "AutoConf",
+                       "Host Selected",
+               };
+
+               const char *addressformat[] = {
+                       "Unknown",
+                       "Ipv4",
+                       "Ipv6",
+               };
+
+               printf("%sProtocol Records (%02d):\n", prefix, count);
+               for (i=0; i < count; i++) {
+                       rid = (u8)rec[PROTO_REC_ID];
+                       rlen = (u8)rec[PROTO_REC_LEN];
+                       rdata = &rec[PROTO_REC_DATA];
+
+                       if (rid == PROTO_OEM)
+                               rid = PROTO_OEM_MAP;
+
+                       if (rid >= PROTO_OEM_MAP)
+                               rid = PROTO_UNKNOWN;
+
+                       printf("%s\tProtocol ID: %02x (%s)\n", prefix, rid, 
protocoltypes[rid]);
+
+                       /* Don't decode anything other than redfish for now */
+                       if (rid != PROTO_REDFISH_OVER_IP)
+                               goto next;
+
+                       memcpy(buf, &rdata[REC_UUID], 16);
+
+                       /* Convert UUID to readable characters */
+                       for (j=0, k=0; j < 33; j++, k++) {
+                               if ((j == 8) || (j == 12) || (j == 16) || (j == 
20)) {
+                                       uuid[k] = '-';
+                                       k++;
+                               }
+
+                               if (j & 0x1)
+                                       uuid[k] = (buf[j/2] >> 4) + 0x30;
+                               else
+                                       uuid[k] = (buf[j/2] & 0x0f) + 0x30;
+
+                               if (uuid[j] >= 0x3a)
+                                       uuid[j] += 7;
+                       }
+                       uuid[32] = '\0';
+                       printf("%s\t\tService UUID: %s\n", prefix, uuid);
+
+                       assignval = (u8)rdata[REC_HOST_IP_ASGN_TYPE];
+                       if (assignval > IP_HOSTSEL)
+                               assignval = IP_UNKNOWN;
+                       printf("%s\t\tHost IP Assignment Type: %s\n", prefix, 
assigntype[assignval]);
+
+                       addrtype = (u8)rdata[REC_HOST_IP_ADDR_FMT];
+                       if (addrtype > ADDR_IPV6)
+                               addrtype = ADDR_UNKNOWN;
+                       printf("%s\t\tHost IP Address Format: %s\n", prefix, 
addressformat[addrtype]);
+
+                       /* We only use the Host IP Address and Mask if the 
assignment type is static */
+                       if ((assignval == IP_STATIC) || (assignval == 
IP_AUTOCONF)) {
+                               /* Prints the Host IP Address */
+                               printf("%s\t\t%s Address: %s\n", prefix,
+                                     (addrtype == 0x1 ? "Ipv4" : "Ipv6"),
+                                     (addrtype == 0x1 ?
+                                       inet_ntop(AF_INET, (char 
*)&rdata[REC_HOST_ADDR], (char *)buf, 64) :
+                                       inet_ntop(AF_INET6, (char 
*)&rdata[REC_HOST_ADDR], (char *)buf, 64)));
+
+                               /* Prints the Host IP Mask */
+                               printf("%s\t\t%s Mask: %s\n", prefix,
+                                     (addrtype == ADDR_IPV4 ? "Ipv4" : "Ipv6"),
+                                     (addrtype == ADDR_IPV4 ?
+                                       inet_ntop(AF_INET, (char 
*)&rdata[REC_HOST_MASK], (char *)buf, 64) :
+                                       inet_ntop(AF_INET6, (char 
*)&rdata[REC_HOST_MASK], (char *)buf, 64)));
+                       }
+
+                       /* Get the Redfish Service IP Discovery Type */
+                       assignval = (u8)rdata[REC_RFSH_DISC_TYPE];
+                       if (assignval > IP_HOSTSEL)
+                               assignval = 0;
+
+                       /* Redfish Service IP Discovery type Mirrors Host IP 
Assignment type */
+                       printf("%s\t\tRedfish Service IP Discovery Type: %s\n", 
prefix, assigntype[assignval]);
+
+                       /* Get the Redfish Service IP Address Format */
+                       addrtype = (u8)rdata[REC_RFSH_ADDR_FMT];
+                       if (addrtype > ADDR_IPV6)
+                               addrtype = ADDR_UNKNOWN;
+
+                       printf("%s\t\tRedfish Service IP Address Format: %s\n", 
prefix, addressformat[addrtype]);
+                       if ((assignval == IP_STATIC)  || (assignval == 
IP_AUTOCONF)) {
+                               u16 port;
+                               u32 vlan;
+                               /* Prints the Redfish Service Address */
+                               printf("%s\t\t%s Redfish Service Address: 
%s\n", prefix,
+                                     (addrtype == ADDR_IPV4 ? "Ipv4" : "Ipv6"),
+                                     (addrtype == ADDR_IPV4 ?
+                                       inet_ntop(AF_INET, (char 
*)&rdata[REC_RFSH_ADDR], (char *)buf, 64) :
+                                       inet_ntop(AF_INET6, (char 
*)&rdata[REC_RFSH_ADDR], (char *)buf, 64)));
+
+                               /* Prints the Redfish Service Mask */
+                               printf("%s\t\t%s Redfish Service Mask: %s\n", 
prefix,
+                                     (addrtype == ADDR_IPV4 ? "Ipv4" : "Ipv6"),
+                                     (addrtype == ADDR_IPV4 ?
+                                       inet_ntop(AF_INET, (char 
*)&rdata[REC_RFSH_MASK], (char *)buf, 64) :
+                                       inet_ntop(AF_INET6, (char 
*)&rdata[REC_RFSH_MASK], (char *)buf, 64)));
+
+                               port = WORD(&rdata[REC_RFSH_PORT]);
+                               vlan = DWORD(&rdata[REC_RFSH_VLAN]);
+                               printf("%s\t\tRedfish Service Port: %d\n", 
prefix, port);
+                               printf("%s\t\tRedfish Service Vlan: %d\n", 
prefix, vlan);
+
+                       }
+
+                       hlen = (u8)rdata[REC_RFSH_HOST_LEN];
+                       memcpy(hname, &rdata[REC_RFSH_HOSTNAME], hlen);
+                       hname[hlen] = '\0';
+                       printf("%s\t\tRedfish Service Hostname: %s\n", prefix, 
hname);
+next:
+                       rec = rec + rlen +1;
+               }
+       }
+
+       return;
+
+}
+
 /*
  * Main
  */
@@ -4582,22 +4920,26 @@ static void dmi_decode(const struct dmi_header *h, u16 
ver)
 
                case 42: /* 7.43 Management Controller Host Interface */
                        printf("Management Controller Host Interface\n");
-                       if (h->length < 0x05) break;
-                       printf("\tInterface Type: %s\n",
-                               
dmi_management_controller_host_type(data[0x04]));
-                       /*
-                        * There you have a type-dependent, variable-length
-                        * part in the middle of the structure, with no
-                        * length specifier, so no easy way to decode the
-                        * common, final part of the structure. What a pity.
-                        */
-                       if (h->length < 0x09) break;
-                       if (data[0x04] == 0xF0)         /* OEM */
-                       {
-                               printf("\tVendor ID: 0x%02X%02X%02X%02X\n",
-                                       data[0x05], data[0x06], data[0x07],
-                                       data[0x08]);
-                       }
+
+                       if (ver < 0x300) {
+                               if (h->length < 0x05) break;
+                               printf("\tInterface Type: %s\n",
+                                       
dmi_management_controller_host_type(data[0x04]));
+                               /*
+                                * There you have a type-dependent, 
variable-length
+                                * part in the middle of the structure, with no
+                                * length specifier, so no easy way to decode 
the
+                                * common, final part of the structure. What a 
pity.
+                                */
+                               if (h->length < 0x09) break;
+                               if (data[0x04] == 0xF0)         /* OEM */
+                               {
+                                       printf("\tVendor ID: 
0x%02X%02X%02X%02X\n",
+                                               data[0x05], data[0x06], 
data[0x07],
+                                               data[0x08]);
+                               }
+                       } else
+                               decode_management_controller_structure(h, 
"\t\t");
                        break;
 
                case 43: /* 7.44 TPM Device */
-- 
2.17.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]