dmidecode-devel
[Top][All Lists]
Advanced

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

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


From: Neil Horman
Subject: [dmidecode] [PATCH v2] update dmidecode to parse Modern Management Controller blocks
Date: Thu, 2 Aug 2018 10:55:15 -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)
---
 dmidecode.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 316 insertions(+), 16 deletions(-)

diff --git a/dmidecode.c b/dmidecode.c
index fa6ecf1..ea7619f 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -63,6 +63,7 @@
 #include <strings.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #ifdef __FreeBSD__
 #include <errno.h>
@@ -3447,6 +3448,301 @@ 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 7
+
+/*
+ * 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
+
+/*
+ * 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_NET_HOST_IFC 0x40
+
+/*
+ * Interface specific data values
+ */
+#define IFC_DEVICE_UNKNOWN 0x0
+#define IFC_DEVICE_USB 0x2
+#define IFC_DEVICE_PCI 0x3
+#define IFC_DEVICE_OEM_BASE 0x80
+
+/*
+ * Protocol record data values
+ */
+#define REDFISH_OVER_IP 0x4
+
+/*
+ * 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 < 0x9) {
+               printf("%s Invalid structure\n", prefix);
+               return;
+       }
+
+       printf("%sHost Interface Type: ", prefix);
+       if (type != MCH_NET_HOST_IFC)
+               printf("Unknown\n");
+       else
+               printf("Network\n");
+
+
+       if (len != 0) {
+               type = data[IFC_DEVICE_TYPE];
+               if (type >= IFC_DEVICE_OEM_BASE)
+                       type = IFC_DEVICE_UNKNOWN;
+
+               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, (unsigned 
short)usbdata[USB_VENDOR]);
+                       printf("%s\tidProduct: 0x%04x\n", prefix, (unsigned 
short)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, (unsigned 
short)pcidata[PCI_VENDOR]);
+                       printf("%s\tDeviceID: 0x%04x\n", prefix, (unsigned 
short)pcidata[PCI_DEVICE]);
+                       printf("%s\tSubVendorID: 0x%04x\n", prefix, (unsigned 
short)pcidata[PCI_SUBVENDOR]);
+                       printf("%s\tSubDeviceID: 0x%04x\n", prefix, (unsigned 
short)pcidata[PCI_SUBDEVICE]);
+               }
+               /* 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 *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 != REDFISH_OVER_IP) {
+                               printf("%s\tProtocol ID: %02x (Unknown)\n", 
prefix, rid);
+                               goto next;
+                       }
+
+                       printf("%s\tProtocol ID: Redfish over IP\n", prefix);
+                       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 = (u8)rdata[REC_RFSH_PORT];
+                               vlan = (u16)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 +4878,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]