dmidecode-devel
[Top][All Lists]
Advanced

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

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


From: Neil Horman
Subject: [dmidecode] [PATCH v4] update dmidecode to parse Modern Management Controller blocks
Date: Mon, 13 Aug 2018 12:02:41 -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.
V3->V4) Moved type 42 defines to more  appropriate section

        Removed defines to avoid namespace clashes

        Renamed function to dmi_parse_controller_structure

        Renamed PCI[e] to PCI/PCIe

        Added check to make sure structure length is sane

        Consolidated Host Interface parsing to 
dmi_management_controller_host_type

        Restrict the controller parsing structure to only decode network
        interface types

        Validate that strucure recorded length is enough to decode ifc
        specific data

        Removed bString comment

        Corrected protocol count comment

        Separated protocol parsing to its own function

        Adjusted hlen size

        Fixed Ip/IP casing

        Test each protocol record for containment in overall struct
        length

        Use dmi_system_uuid

        Converted ennumeration string lookups to their own function

        Guaranteed the non-null-ness of inet_ntop (note, inet_ntop is
        POSIX-2001 compliant and so should be very portable)

        Cleaned up host name copy using printf string precision
        specifier

        Cleaned up smbios version check

        Fixed record cursor advancement

        Misc cleanups
---
 dmidecode.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 345 insertions(+), 15 deletions(-)

diff --git a/dmidecode.c b/dmidecode.c
index 76faed9..f7f1a9e 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -56,6 +56,10 @@
  *  - "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" (DMTF DSP0270)
+ *    https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf
+ *  - "DMTF SMBIOS Specification" (DMTF DSP0134)
+ *    
https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
  */
 
 #include <stdio.h>
@@ -63,6 +67,7 @@
 #include <strings.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #ifdef __FreeBSD__
 #include <errno.h>
@@ -3379,6 +3384,7 @@ static void dmi_additional_info(const struct dmi_header 
*h, const char *prefix)
 static const char *dmi_management_controller_host_type(u8 code)
 {
        /* DMTF DSP0239 (MCTP) version 1.1.0 */
+       /* DMTF DSP0134 (SMBIOS version 3.1.1) */
        static const char *type[] = {
                "KCS: Keyboard Controller Style", /* 0x02 */
                "8250 UART Register Compatible",
@@ -3391,7 +3397,11 @@ static const char 
*dmi_management_controller_host_type(u8 code)
 
        if (code >= 0x02 && code <= 0x08)
                return type[code - 0x02];
-       if (code == 0xF0)
+       else if (code <= 0x3F)
+               return "MCTP";
+       else if (code == 0x40)
+               return "Network";
+       else if (code == 0xF0)
                return "OEM";
        return out_of_spec;
 }
@@ -3447,6 +3457,321 @@ static void dmi_tpm_characteristics(u64 code, const 
char *prefix)
                                prefix, characteristics[i - 2]);
 }
 
+/*
+ * DSP0134: 7.43.2: Protocol Record Types
+ */
+static const char *dmi_protocol_record_type(u8 type)
+{
+       const char *protocoltypes[] = {
+               "Reserved",
+               "Reserved",
+               "IPMI",
+               "MCTP",
+               "Redfish over IP",
+       };
+
+       if (type == 0xF0)
+               return "OEM";
+       else if (type <= 0x4)
+               return protocoltypes[type];
+       return out_of_spec;
+}
+
+/*
+ * DSP0270: 8.6: Protocol IP Assignment types
+ */
+static const char *dmi_protocol_assignment_type(u8 type)
+{
+       const char *assigntype[] = {
+               "Unknown",
+               "Static",
+               "DHCP",
+               "AutoConf",
+               "Host Selected",
+       };
+
+       if (type <= 0x4)
+               return assigntype[type];
+       return out_of_spec;
+}
+
+/*
+ * DSP0270: 8.6: Protocol IP Address type
+ */
+static const char *dmi_address_type(u8 type)
+{
+       const char *addressformat[] = {
+               "Unknown",
+               "IPv4",
+               "IPv6",
+       };
+
+       if (type <= 0x2)
+               return addressformat[type];
+       return out_of_spec;
+}
+
+static void dmi_parse_protocol_record(const char *prefix, u8 *rec)
+{
+       u8 rid;
+       u8 *rdata;
+       u8 buf[64];
+       u8 aval;
+       u8 addrtype;
+       u8 hlen;
+       const char *addr;
+       int af;
+
+       /* DSP0270: 8.5: Protocol Identifier*/
+       rid = rec[0x0];
+       /* DSP0270: 8.5: Protocol Record Data */
+       rdata = &rec[0x2];
+
+       /*
+        * DSP0134: 7.43.2: If the protocol type is OEM defined,
+        * Map it down to the OEM index in our prtocol types
+        * array.  Otherwise, if its larger than the last
+        * defined type on the list, index it as unknnown
+        */
+       printf("%s\tProtocol ID: %02x (%s)\n", prefix, rid, 
dmi_protocol_record_type(rid));
+
+       /*
+        * Don't decode anything other than redfish for now
+        * Note 0x4 is Redfish over IP in DSP0134: 7.43.2
+        * and DSP0270: 8.5
+        */
+       if (rid != 0x4)
+               return;
+
+       /*
+        * DSP0270: 8.6: Redfish Over IP Service UUID
+        * Note: ver is hardcoded to 0x311 here just for
+        * convienience.  It could get passed from the smbios
+        * header, but thats alot of passing of pointers just
+        * to get that info, and the only thing its used for is
+        * to determine the endianess of the field.  since we only
+        * do this parsing on versions of smbios after 3.1.1, and the 
+        * endianess of the field is alway little after version 2.6.0
+        * we can just pick a sufficiently recent version here
+        */
+       printf("%s\t\tService UUID: ", prefix);
+       dmi_system_uuid(&rdata[0], 0x311);
+       printf("\n");
+
+       /*
+        * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type
+        * Note, using decimal indicies here, as the DSP0270
+        * uses decimal, so as to make it more comparable
+        */
+       aval = rdata[16];
+
+       printf("%s\t\tHost IP Assignment Type: %s\n", prefix,
+                                       dmi_protocol_assignment_type(aval));
+
+       /*
+        * DSP0270: 8.6: Redfish Over IP Host Address format
+        */
+       addrtype = (u8)rdata[17];
+
+       printf("%s\t\tHost IP Address Format: %s\n", prefix,
+                                                    
dmi_address_type(addrtype));
+
+       /* DSP0270: 8.6 IP Assignment types */
+       /* We only use the Host IP Address and Mask if the assignment type is 
static */
+       if (aval == 0x1 || aval == 0x3)
+       {
+               /* DSP0270: 8.6: the Host IPV[4|6] Address */
+               af = addrtype == 0x1 ? AF_INET : AF_INET6;
+               addr = inet_ntop(af, &rdata[18], (char *)buf, 64);
+               addr = addr ? addr: out_of_spec;
+               printf("%s\t\t%s Address: %s\n", prefix,
+                     (addrtype == 0x1 ? "IPv4" : "IPv6"), addr);
+
+               /* DSP0270: 8.6: Prints the Host IPV[4|6] Mask */
+               addr = inet_ntop(af, &rdata[34], (char *)buf, 64);
+               addr = addr ? addr : out_of_spec;
+               printf("%s\t\t%s Mask: %s\n", prefix,
+                     (addrtype == 0x1 ? "IPv4" : "IPv6"), addr);
+       }
+
+       /* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */
+       aval = rdata[50];
+
+       /* Redfish Service IP Discovery type mirrors Host IP Assignment type */
+       printf("%s\t\tRedfish Service IP Discovery Type: %s\n", prefix,
+                                       dmi_protocol_assignment_type(aval));
+
+       /* DSP0270: 8.6: Get the Redfish Service IP Address Format */
+       addrtype = rdata[51];
+
+       printf("%s\t\tRedfish Service IP Address Format: %s\n", prefix,
+                                                               
dmi_address_type(addrtype));
+       if (aval == 0x1 || aval == 0x3)
+       {
+               u16 port;
+               u32 vlan;
+
+               af = addrtype == 0x1 ? AF_INET : AF_INET6;
+               addr = inet_ntop(af, &rdata[52], (char *)buf, 64);
+               addr = addr ? addr : out_of_spec; /* Ensure the string is 
non-null */
+
+               /* DSP0270: 8.6: Prints the Redfish IPV[4|6]Service Address */
+               printf("%s\t\t%s Redfish Service Address: %s\n", prefix,
+                     (addrtype == 0x1 ? "IPv4" : "IPv6"), addr);
+
+               /* DSP0270: 8.6: Prints the Redfish IPV[4|6] Service Mask */
+               addr = inet_ntop(af, &rdata[68], (char *)buf, 64);
+               addr = addr ? addr : out_of_spec;
+               printf("%s\t\t%s Redfish Service Mask: %s\n", prefix,
+                     (addrtype == 0x1 ? "IPv4" : "IPv6"), addr);
+
+               /* DSP0270: 8.6: Redfish vlan and port info */
+               port = WORD(&rdata[84]);
+               vlan = DWORD(&rdata[86]);
+               printf("%s\t\tRedfish Service Port: %u\n", prefix, port);
+               printf("%s\t\tRedfish Service Vlan: %u\n", prefix, vlan);
+       }
+
+       /* DSP0270: 8.6: Redfish host length and name */
+       hlen = rdata[90];
+       printf("%s\t\tRedfish Service Hostname: %*s\n", prefix, hlen, 
&rdata[91]);
+}
+
+/*
+ * DSP0270: 8.3: Device type ennumeration
+ */
+static const char *dmi_parse_device_type(u8 type)
+{
+       const char *devname[] = {
+               "Unknown",
+               "Unknown",
+               "USB",
+               "PCI/PCIe",
+       };
+
+       if (type >= 0x80)
+               return "OEM";
+
+       if (type <= 0x3)
+               return devname[type];
+       return out_of_spec;
+}
+
+static void dmi_parse_controller_structure(const struct dmi_header *h,
+                                          const char *prefix)
+{
+       int i;
+       u8 *data = h->data;
+       /* Host interface type */
+       u8 type = data[0x4];
+       /* Host Interface specific data length */
+       u8 len = data[0x5];
+       u8 count;
+
+       /*
+        * DSP0134: Minimum length of this struct is 0xB bytes
+        */
+       if (h->length < 0xB)
+               return;
+
+       /*
+        * Also need to ensure that the interface specific data length
+        * plus the size of the structure to that point don't exceed
+        * the defined length of the structure, or we will overrun its
+        * bounds
+        */
+       if ((len + 0x7) > h->length)
+               return;
+
+       printf("%sHost Interface Type: %s\n", prefix,
+                                    dmi_management_controller_host_type(type));
+
+       /*
+        * The following decodes are code for Network interface host types only
+        * As defined in DSP0270
+        */
+       if (type != 0x40)
+               return;
+
+       if (len != 0)
+       {
+               /* DSP0270: 8.3 Table 2: Device Type */
+               type = data[0x6];
+
+               printf("%sDevice Type: %s\n", prefix, 
dmi_parse_device_type(type));
+               if ((type == 0x2) && (len >= 6))
+               {
+                       /* USB Device Type - need at least 6 bytes */
+                       u8 *usbdata = &data[0x7];
+                       /* USB Device Descriptor: idVendor */
+                       printf("%s\tidVendor: 0x%04x\n", prefix, 
WORD(&usbdata[0x0]));
+                       /* USB Device Descriptor: idProduct */
+                       printf("%s\tidProduct: 0x%04x\n", prefix, 
WORD(&usbdata[0x2]));
+                       printf("%s\tSerialNumber:\n", prefix);
+                       /* USB Device Descriptor: bDescriptor */
+                       printf("%s\t\tbDescriptor: 0x%02x\n", prefix, 
usbdata[0x5]);
+               }
+               else if ((type == 0x3) && (len >= 8))
+               {
+                       /* PCI Device Type - Need at least 8 bytes*/
+                       u8 *pcidata = &data[0x7];
+                       /* PCI Device Descriptor: VendorID */
+                       printf("%s\tVendorID: 0x%04x\n", prefix, 
WORD(&pcidata[0x0]));
+                       /* PCI Device Descriptor: DeviceID */
+                       printf("%s\tDeviceID: 0x%04x\n", prefix, 
WORD(&pcidata[0x2]));
+                       /* PCI Device Descriptor: PCI SubvendorID */
+                       printf("%s\tSubVendorID: 0x%04x\n", prefix, 
WORD(&pcidata[0x4]));
+                       /* PCI Device Descriptor: PCI SubdeviceID */
+                       printf("%s\tSubDeviceID: 0x%04x\n", prefix, 
WORD(&pcidata[0x6]));
+               }
+               else if ((type == 0x4) && (len >= 4))
+               {
+                       /* OEM Device Type - Need at least 4 bytes */
+                       u32 *oemdata = (u32 *)&data[0x7];
+                       /* OEM Device Descriptor: IANA */
+                       printf("%s\t Vendor ID: 0x%08x\n", prefix, 
DWORD(&oemdata[0x0]));
+               }
+               /* Don't mess with unknown types for now */
+       }
+
+       /*
+        * DSP0270: 8.2 and 8.5: Protcol record count and protocol records
+        * Move to the Protocol Count Record
+        * data[0x6] points to the start of the interface specific
+        * data, and len is the length of that region
+        */
+       data = &data[0x6+len];
+       len = len+0x6;
+
+       /* Get the protocol records count */
+       count = (u8)data[0x0];
+       if (count)
+       {
+               u8 *rec = &data[0x1];
+               for (i = 0; i < count; i++)
+               {
+                       /*
+                        * Need to ensure that this record doesn't overrun
+                        * the total length of the type 42 struct
+                        */
+                       if (len + rec[1] > h->length)
+                               return;
+                       len += rec[1];
+
+                       dmi_parse_protocol_record(prefix, rec);
+                       /*
+                        * DSP0270: 8.6
+                        * Each record is rec[1] bytes long, starting at the
+                        * data byte immediately following the length field
+                        * That means we need to add the byte for the rec id,
+                        * the byte for the length field, and the value of the
+                        * length field itself
+                        */
+                       rec += rec[1] + 2;
+               }
+       }
+}
+
 /*
  * Main
  */
@@ -4582,22 +4907,27 @@ 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 */
+                       if (ver < 0x0302)
                        {
-                               printf("\tVendor ID: 0x%02X%02X%02X%02X\n",
-                                       data[0x05], data[0x06], data[0x07],
-                                       data[0x08]);
+                               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
+                               dmi_parse_controller_structure(h, "\t");
                        break;
 
                case 43: /* 7.44 TPM Device */
-- 
2.17.1




reply via email to

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