/* $NetBSD: devpath3.c,v 1.3 2025/02/25 22:11:36 christos Exp $ */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __RCSID("$NetBSD: devpath3.c,v 1.3 2025/02/25 22:11:36 christos Exp $"); #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "devpath.h" #include "devpath3.h" #include "utils.h" #define easprintf (size_t)easprintf #if 0 GUID= EFI_PC_ANSI_GUID GUID= EFI_VT_100_GIUD GUID= EFI_VT_100_PLUS_GUID GUID= EFI_VT_UTF8_GUID GUID= DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL GUID= EFI_DEBUGPORT_PROTOCOL_GUID GUID= d487ddb4-008b-11d9-afdc-001083ffca4d #endif /* Used in sub-type 10 */ #define EFI_PC_ANSI_GUID\ {0xe0c14753,0xf9be,0x11d2,0x9a,0x0c,{0x00,0x90,0x27,0x3f,0xc1,0x4d}} #define EFI_VT_100_GUID\ {0xdfa66065,0xb419,0x11d3,0x9a,0x2d,{0x00,0x90,0x27,0x3f,0xc1,0x4d}} #define EFI_VT_100_PLUS_GUID\ {0x7baec70b,0x57e0,0x4c76,0x8e,0x87,{0x2f,0x9e,0x28,0x08,0x83,0x43}} #define EFI_VT_UTF8_GUID\ {0xad15a0d6,0x8bec,0x4acf,0xa0,0x73,{0xd0,0x1d,0xe7,0x7e,0x2d,0x88}} #define EFI_DEBUGPORT_PROTOCOL_GUID \ {0xeba4e8d2,0x3858,0x41ec,0xa2,0x81,{0x26,0x47,0xba,0x96,0x60,0xd0}} #define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL \ {0x37499a9d,0x542f,0x4c89,0xa0,0x26,{0x35,0xda,0x14,0x20,0x94,0xe4}} #define EFI_VENDOR_SAS\ {0xd487ddb4,0x008b,0x11d9,0xaf,0xdc,{0x00,0x10,0x83,0xff,0xca,0x4d}} /************************************************************************/ static inline char * upcase(char *str) { for (char *p = str; *p != '\0'; p++) *p = (char)toupper((int)(unsigned char)*p); return str; } static inline char * proto_name(uint16_t proto) /* See RFC3233/RFC1700 */ { struct protoent *ent; char *name; char *bp; ent = getprotobynumber(proto); if (ent == NULL) { easprintf(&bp, "0x%04x", proto); return bp; } name = estrdup(ent->p_name); return upcase(name); } static inline char * ipv4_addr(uint32_t addr) { char *bp; bp = ecalloc(1, INET_ADDRSTRLEN); if (inet_ntop(AF_INET, &addr, bp, INET_ADDRSTRLEN) == NULL) err(EXIT_FAILURE, "%s: inet_ntop(AF_INET)", __func__); return bp; } static inline char * ipv4_type(uint8_t type) { switch (type) { case 0: return estrdup("DHCP"); case 1: return estrdup("Static"); default: return estrdup("Unknown"); } } static inline char * ipv6_addr(struct in6_addr *addr) { char *bp; bp = ecalloc(1, INET6_ADDRSTRLEN); if (inet_ntop(AF_INET6, addr, bp, INET6_ADDRSTRLEN) == NULL) err(EXIT_FAILURE, "%s: inet_ntop(AF_INET6)", __func__); return bp; } static inline char * ipv6_type(uint8_t type) { switch (type) { case 0: return estrdup("Static"); case 1: return estrdup("StatelessAutoConfigure"); case 2: return estrdup("StatefulAutoConfigure"); default: return estrdup("Unknown"); } } /************************************************************************ * Type 3 - Messaging Device Path ************************************************************************/ static void devpath_msg_atapi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.1 */ struct { /* Sub-Type 1 */ devpath_t hdr; /* Length = 8 */ uint8_t IsSecondary; uint8_t IsSlave; uint16_t LUN; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 8); path->sz = easprintf(&path->cp, "ATAPI(%u,%u,%u)", p->IsSecondary, p->IsSlave, p->LUN); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(IsSecondary: %u\n) DEVPATH_FMT(IsPrimary: %u\n) DEVPATH_FMT(LUN: %u\n), DEVPATH_DAT_HDR(dp), p->IsSecondary, p->IsSlave, p->LUN); } } static void devpath_msg_scsi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.2 */ struct { /* Sub-Type 2 */ devpath_t hdr; /* Length = 8 */ uint16_t SCSITargetID; /* PUN */ uint16_t SCSILogicalUnitNum; /* LUN */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 8); path->sz = easprintf(&path->cp, "SCSI(%u,%u)", p->SCSITargetID, p->SCSILogicalUnitNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(SCSITargetID: %u\n) DEVPATH_FMT(SCSILogicalUnitNum: %u\n), DEVPATH_DAT_HDR(dp), p->SCSITargetID, p->SCSILogicalUnitNum); } } static void devpath_msg_fibre(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.3 */ struct { /* Sub-Type 3 */ devpath_t hdr; /* Length = 24 */ uint32_t Reserved; uint64_t WWName; uint64_t LUN; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); path->sz = easprintf(&path->cp, "Fibre(0x%016" PRIx64 ",0x%016" PRIx64 ")", p->WWName, p->LUN); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Reserved: 0x%08x\n) DEVPATH_FMT(WWName:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(LUN:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->Reserved, p->WWName, p->LUN); } } static void devpath_msg_11394(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.4 */ struct { /* Sub-Type 4 */ devpath_t hdr; /* Length = 16 */ uint32_t Reserved; uint64_t GUID; /* XXX: not an EFI_GUID */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 16); path->sz = easprintf(&path->cp, "11394(0x%016" PRIx64 ")", p->GUID); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Reserved: 0x%08x\n) DEVPATH_FMT(GUID:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->Reserved, p->GUID); } } static void devpath_msg_usb(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.5 */ struct { /* Sub-Type 5 */ devpath_t hdr; /* Length = 6 */ uint8_t USBParentPortNum; uint8_t USBInterfaceNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 6); path->sz = easprintf(&path->cp, "USB(%u,%u)", p->USBParentPortNum, p->USBInterfaceNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(USBParentPortNum: %u\n) DEVPATH_FMT(USBInterfaceNum: %u\n), DEVPATH_DAT_HDR(dp), p->USBParentPortNum, p->USBInterfaceNum); } } static void devpath_msg_i2o(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.9 */ struct { /* Sub-Type 6 */ devpath_t hdr; /* Length = 8 */ uint32_t TID; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 8); path->sz = easprintf(&path->cp, "I2O(0x%08x)", p->TID); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(TID: 0x%08x\n), DEVPATH_DAT_HDR(dp), p->TID); } } #define INFINIBAND_FLAG_BITS \ "\177\020" \ "b\x0""Service\0" \ "b\x1""BootEnv\0" \ "b\x2""ConProto\0" \ "b\x3""Storage\0" \ "b\x4""NetWork\0" \ "f\x5\11""Resvd\0" static void devpath_msg_infiniband(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.14 */ struct { /* Sub-Type 9 */ devpath_t hdr; /* Length = 48 */ uint32_t Flags; uuid_t GUID; uint64_t ServiceID; uint64_t PortID; uint64_t DeviceID; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 48); char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); path->sz = easprintf(&path->cp, "Infiniband(%#x,%s,0x%016" PRIx64 ",0x%016" PRIx64 ",0x%016" PRIx64 ")", p->Flags, uuid_str, p->ServiceID, p->PortID, p->DeviceID); if (dbg != NULL) { char flags_str[128]; snprintb(flags_str, sizeof(flags_str), INFINIBAND_FLAG_BITS, p->Flags); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Flags: %s\n) DEVPATH_FMT(GUID: %s\n) DEVPATH_FMT(ServiceID:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(PortID:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(DeviceID:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), flags_str, uuid_str, p->ServiceID, p->PortID, p->DeviceID); } } /**************************************** * Sub-Type 10 variants */ static void devpath_msg_debugport(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 18.3.7 */ struct { /* Sub-Type 10 */ devpath_t hdr; /* Length = 20 */ uuid_t GUID; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); path->sz = easprintf(&path->cp, "DebugPort()"); if (dbg != NULL) { char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(GUID: %s\n), DEVPATH_DAT_HDR(dp), uuid_str); } } static void devpath_msg_uartflowctl(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.17 */ struct { /* Sub-Type 10 */ devpath_t hdr; /* Length = 24 */ uuid_t GUID; uint32_t FlowCtl; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); const char *fc_str; switch (p->FlowCtl) { case 0: fc_str = "None"; break; case 1: fc_str = "Hardware"; break; case 2: fc_str = "XonXoff"; break; default: fc_str = "????"; break; } path->sz = easprintf(&path->cp, "UartFlowCtrl(%s)", fc_str); if (dbg != NULL) { char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(GUID: %s\n) DEVPATH_FMT(FlowCtl: 0x%04x(%s)\n), DEVPATH_DAT_HDR(dp), uuid_str, p->FlowCtl, fc_str); } } /**************************************** * Macros for dealing with SAS/SATA device and topology info field. */ #define SASINFO_BYTES_MASK __BITS(3,0) #define SASINFO_SATA_BIT __BIT(4) #define SASINFO_EXTERNAL_BIT __BIT(5) #define SASINFO_EXPANDER_BIT __BIT(6) #define SASINFO_BYTES(b) __SHIFTOUT((b), SASINFO_BYTES_MASK) #define SASINFO_IS_SATA(b) ((b) % SASINFO_SATA_BIT) #define SASINFO_IS_EXTERNAL(b) ((b) % SASINFO_EXTERNAL_BIT) #define SASINFO_IS_EXPANDER(b) ((b) % SASINFO_EXPANDER_BIT) #define SASINFO_SASSATA(b) (SASINFO_IS_SATA(b) ? "SATA" : "SAS") #define SASINFO_EXTERNAL(b) (SASINFO_IS_EXTERNAL(b) ? "External" : "Internal") #define SASINFO_EXPANDER(b) (SASINFO_IS_EXPANDER(b) ? "Expander" : "direct") /****************************************/ static void devpath_msg_sas(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.18 */ struct { /* Sub-Type 10 */ devpath_t hdr; /* Length = 44 */ uuid_t GUID; uint32_t resv; uint64_t addr; /* display as big-endian */ uint64_t LUN; /* display as big-endian */ union { uint8_t b[2]; uint16_t val; } __packed info; /* device/topology info */ uint16_t RTP; /* Relative Target Port */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 44); /* * There seems to be a discrepency between the display * examples in 10.3.4.18, 10.3.4.18.4, and Table 10.67. The * first example in 10.3.4.18 also refers to a third number * (RTP) which isn't present. I also find the info in Table * 10.67 a bit unclear. */ if (SASINFO_BYTES(p->info.b[0]) == 0) { path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64 ",0x%064" PRIx64 ")", htobe64(p->addr), htobe64(p->LUN)); } else if (SASINFO_BYTES(p->info.b[0]) == 1) { if (SASINFO_IS_SATA(p->info.b[0])) { path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64 ",0x%064" PRIx64 ",SATA)", htobe64(p->addr), htobe64(p->LUN)); } else { path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64 ",SAS)", htobe64(p->addr)); } } else { assert(SASINFO_BYTES(p->info.b[0]) == 2); uint drivebay = p->info.b[1] + 1; path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64 ",0x%064" PRIx64 ",0x%04x,%s,%s,%s,%d,0x%04x)", htobe64(p->addr), htobe64(p->LUN), p->RTP, SASINFO_SASSATA(p->info.b[0]), SASINFO_EXTERNAL(p->info.b[0]), SASINFO_EXPANDER(p->info.b[0]), drivebay, p->resv); } if (dbg != NULL) { char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(GUID: %s\n) DEVPATH_FMT(resv: 0x%08x\n) DEVPATH_FMT(addr:) " 0x%064" PRIx64 "(0x%064" PRIx64 ")\n" DEVPATH_FMT(LUN:) " 0x%064" PRIx64 "(0x%064" PRIx64 ")\n" DEVPATH_FMT(info: 0x%02x 0x%02x\n) DEVPATH_FMT(RPT: 0x%04x\n), DEVPATH_DAT_HDR(dp), uuid_str, p->resv, p->addr, htobe64(p->addr), p->LUN, htobe64(p->LUN), p->info.b[0], p->info.b[1], p->RTP); } } static struct vendor_type { uuid_t GUID; void(*fn)(devpath_t *, devpath_elm_t *, devpath_elm_t *); const char *name; } * devpath_msg_vendor_type(uuid_t *uuid) { static struct vendor_type tbl[] = { { .GUID = EFI_PC_ANSI_GUID, .fn = NULL, .name = "VenPcAnsi", }, { .GUID = EFI_VT_100_GUID, .fn = NULL, .name = "VenVt100", }, { .GUID = EFI_VT_100_PLUS_GUID, .fn = NULL, .name = "VenVt100Plus", }, { .GUID = EFI_VT_UTF8_GUID, .fn = NULL, .name = "VenUtf8", }, /********/ /* See 18.3.7 */ { .GUID = EFI_DEBUGPORT_PROTOCOL_GUID, .fn = devpath_msg_debugport, .name = "DebugPort", }, /********/ /* See 10.3.4.17 */ { .GUID = DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL, .fn = devpath_msg_uartflowctl, .name = "UartFlowCtrl", }, /* See 10.3.4.18 */ { .GUID = EFI_VENDOR_SAS, .fn = devpath_msg_sas, .name = "SAS", }, }; for (size_t i = 0; i < __arraycount(tbl); i++) { if (memcmp(uuid, &tbl[i].GUID, sizeof(*uuid)) == 0) { return &tbl[i]; } } return NULL; } static void devpath_msg_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.16 */ struct { /* Sub-Type 10 */ devpath_t hdr; /* Length = 20 + n */ uuid_t GUID; uint8_t data[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; size_t len; struct vendor_type *vt; char *data_str; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID); len = dp->Length - sizeof(*p); data_str = encode_data(p->data, len); vt = devpath_msg_vendor_type(&p->GUID); if (vt == NULL) { path->sz = easprintf(&path->cp, "VenMsg(%s,%s)", uuid_str, data_str); } else if (vt->fn == NULL) { assert(vt->name != NULL); path->sz = easprintf(&path->cp, "%s(%s)", vt->name, data_str); } else { vt->fn(dp, path, dbg); return; } if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(GUID: %s\n) DEVPATH_FMT(Data: %s\n), DEVPATH_DAT_HDR(dp), uuid_str, data_str); } free(data_str); } static void devpath_msg_mac(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.10 */ struct { /* Sub-Type 11 */ devpath_t hdr; /* Length = 37 */ uint8_t mac_addr[32]; uint8_t IfType; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 37); size_t addr_len; char *mac_addr; switch (p->IfType) { case 0: case 1: addr_len = 6; break; default: addr_len = 32; break; } #if 0 From: RFC3232 says everything is now online, found here: https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml XXX: Should we make a table so we can show a name? 0 Reserved [RFC5494] 1 Ethernet (10Mb) [Jon_Postel] 2 Experimental Ethernet (3Mb) [Jon_Postel] 3 Amateur Radio AX.25 [Philip_Koch] 4 Proteon ProNET Token Ring [Avri_Doria] 5 Chaos [Gill_Pratt] 6 IEEE 802 Networks [Jon_Postel] 7 ARCNET [RFC1201] 8 Hyperchannel [Jon_Postel] 9 Lanstar [Tom_Unger] 10 Autonet Short Address [Mike_Burrows] 11 LocalTalk [Joyce_K_Reynolds] 12 LocalNet (IBM PCNet or SYTEK LocalNET) [Joseph Murdock] 13 Ultra link [Rajiv_Dhingra] 14 SMDS [George_Clapp] 15 Frame Relay [Andy_Malis] 16 Asynchronous Transmission Mode (ATM) [[JXB2]] 17 HDLC [Jon_Postel] 18 Fibre Channel [RFC4338] 19 Asynchronous Transmission Mode (ATM) [RFC2225] 20 Serial Line [Jon_Postel] 21 Asynchronous Transmission Mode (ATM) [Mike_Burrows] 22 MIL-STD-188-220 [Herb_Jensen] 23 Metricom [Jonathan_Stone] 24 IEEE 1394.1995 [Myron_Hattig] 25 MAPOS [Mitsuru_Maruyama][RFC2176] 26 Twinaxial [Marion_Pitts] 27 EUI-64 [Kenji_Fujisawa] 28 HIPARP [Jean_Michel_Pittet] 29 IP and ARP over ISO 7816-3 [Scott_Guthery] 30 ARPSec [Jerome_Etienne] 31 IPsec tunnel [RFC3456] 32 InfiniBand (TM) [RFC4391] 33 TIA-102 Project 25 Common Air Interface (CAI) [Jeff Anderson, Telecommunications Industry of America (TIA) TR-8.5 Formulating Group, , June 2004] 34 Wiegand Interface [Scott_Guthery_2] 35 Pure IP [Inaky_Perez-Gonzalez] 36 HW_EXP1 [RFC5494] 37 HFI [Tseng-Hui_Lin] 38 Unified Bus (UB) [Wei_Pan] 39-255 Unassigned 256 HW_EXP2 [RFC5494] 257 AEthernet [Geoffroy_Gramaize] 258-65534 Unassigned 65535 Reserved [RFC5494] #endif mac_addr = encode_data(p->mac_addr, addr_len); path->sz = easprintf(&path->cp, "MAC(%s,%d)", mac_addr, p->IfType); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(MAC_addr: %s\n) DEVPATH_FMT(IfType: %x\n), DEVPATH_DAT_HDR(dp), mac_addr, p->IfType); } free(mac_addr); } static void devpath_msg_ipv4(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.11 */ struct { /* Sub-Type 12 */ devpath_t hdr; /* Length = 27 */ uint32_t LocalIPAddr; uint32_t RemoteIPAddr; uint16_t LocalPort; uint16_t RemotePort; uint16_t Protocol; uint8_t StaticIPAddr; uint32_t GatewayIPAddr; uint32_t SubnetMask; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 27); char *gaddr, *laddr, *raddr, *mask; char *proto, *atype; laddr = ipv4_addr(p->LocalIPAddr); gaddr = ipv4_addr(p->GatewayIPAddr); raddr = ipv4_addr(p->RemoteIPAddr); mask = ipv4_addr(p->SubnetMask); proto = proto_name(p->Protocol); atype = ipv4_type(p->StaticIPAddr); path->sz = easprintf(&path->cp, "IPv4(%s,%s,%s,%s,%s,%s)", raddr, proto, atype, laddr, gaddr, mask); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(LocalIPAddr: 0x%08x(%s)\n) DEVPATH_FMT(RemoteIPAddr: 0x%08x(%s)\n) DEVPATH_FMT(LocalPort: 0x%04x\n) DEVPATH_FMT(RemotePort: 0x%04x\n) DEVPATH_FMT(Protocol: 0x%04x(%s)\n) DEVPATH_FMT(StaticIPAddr: 0x%02x(%s)\n) DEVPATH_FMT(GatewayIPAddr: 0x%08x(%s)\n) DEVPATH_FMT(SubnetMask: 0x%08x(%s)\n), DEVPATH_DAT_HDR(dp), p->LocalIPAddr, laddr, p->RemoteIPAddr, raddr, p->LocalPort, p->RemotePort, p->Protocol, proto, p->StaticIPAddr, atype, p->GatewayIPAddr, gaddr, p->SubnetMask, mask); } free(atype); free(proto); free(mask); free(raddr); free(gaddr); free(laddr); } static void devpath_msg_ipv6(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.12 */ struct { /* Sub-Type 13 */ devpath_t hdr; /* Length = 60 */ struct in6_addr LocalIPAddr; struct in6_addr RemoteIPAddr; uint16_t LocalPort; uint16_t RemotePort; uint16_t Protocol; uint8_t IPAddrOrigin; uint8_t PrefixLength; struct in6_addr GatewayIPAddr; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 60); char *gaddr, *laddr, *raddr; char *proto, *atype; laddr = ipv6_addr(&p->LocalIPAddr); gaddr = ipv6_addr(&p->GatewayIPAddr); raddr = ipv6_addr(&p->RemoteIPAddr); proto = proto_name(p->Protocol); atype = ipv6_type(p->IPAddrOrigin); path->sz = easprintf(&path->cp, "IPv6(%s,%s,%s,%s,%s)", raddr, proto, atype, laddr, gaddr); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(LocalIPAddr: %s\n) DEVPATH_FMT(RemoteIPAddr: %s\n) DEVPATH_FMT(LocalPort: 0x%04x\n) DEVPATH_FMT(RemotePort: 0x%04x\n) DEVPATH_FMT(Protocol: 0x%04x(%s)\n) DEVPATH_FMT(IPAddrOrigin: 0x%02x(%s)\n) DEVPATH_FMT(PrefixLength: 0x%02x\n) DEVPATH_FMT(GatewayIPAddr: %s\n), DEVPATH_DAT_HDR(dp), laddr, raddr, p->LocalPort, p->RemotePort, p->Protocol, proto, p->IPAddrOrigin, atype, p->PrefixLength, gaddr); } free(atype); free(proto); free(raddr); free(gaddr); free(laddr); } static inline const char * uart_parity(uint8_t n) { switch (n) { case 0: return "D"; case 1: return "N"; case 2: return "E"; case 3: return "O"; case 4: return "M"; case 5: return "S"; default: return "?"; } } static inline const char * uart_stopbits(uint8_t n) { switch (n) { case 0: return "D"; case 1: return "1"; case 2: return "1.5"; case 3: return "2"; default: return "?"; } } static void devpath_msg_uart(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.15 */ struct { /* Sub-Type 14 */ devpath_t hdr; /* Length = 19 */ uint32_t Reserved; uint64_t BaudRate; uint8_t DataBits; uint8_t Parity; uint8_t StopBits; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 19); const char *parity, *stopbits; parity = uart_parity(p->Parity); stopbits = uart_stopbits(p->StopBits); path->sz = easprintf(&path->cp, "Uart(%" PRIx64 ",%u,%s,%s)", p->BaudRate, p->DataBits, parity, stopbits); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Reserved: 0x%08x\n) DEVPATH_FMT(BaudRate:) " 0x%016" PRIx64 "\n" DEVPATH_FMT(DataBits: 0x%1x\n) DEVPATH_FMT(Parity: 0x%1x(%s)\n) DEVPATH_FMT(StopBits: 0x%1x(%s)\n), DEVPATH_DAT_HDR(dp), p->Reserved, p->BaudRate, p->DataBits, p->Parity, parity, p->StopBits, stopbits); } } static inline const char * usbclass_name(uint8_t class, uint8_t subclass) { switch (class) { case 1: return "UsbAudio"; case 2: return "UsbCDCControl"; case 3: return "UsbHID"; case 6: return "UsbImage"; case 7: return "UsbPrintr"; case 8: return "UsbMassStorage"; case 9: return "UsbHub"; case 10: return "UsbCDCData"; case 11: return "UsbSmartCard"; case 14: return "UsbVideo"; case 220: return "UsbDiagnostic"; case 224: return "UsbWireless"; case 254: switch (subclass) { case 1: return "UsbDeviceFirmwareUpdate"; case 2: return "UsbIrdaBridge"; case 3: return "UsbTestAndMeasurement"; default: return NULL; } default: return NULL; } } static void devpath_msg_usbclass(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.8 */ struct { /* Sub-Type 15 */ devpath_t hdr; /* Length = 11 */ uint16_t VendorID; uint16_t ProductID; uint8_t DeviceClass; uint8_t DeviceSubClass; uint8_t DeviceProtocol; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 11); const char *name; name = usbclass_name(p->DeviceClass, p->DeviceSubClass); if (name == NULL) { path->sz = easprintf(&path->cp, "UsbClass(0x%04x,0x%04x,0x%02x,0x%02x,0x%02x,)", p->VendorID, p->ProductID, p->DeviceClass, p->DeviceSubClass, p->DeviceProtocol); } else if (p->DeviceClass != 254) { path->sz = easprintf(&path->cp, "%s(0x%04x,0x%04x,0x%02x,0x%02x,)", name, p->VendorID, p->ProductID, p->DeviceSubClass, p->DeviceProtocol); } else { path->sz = easprintf(&path->cp, "%s(0x%04x,0x%04x,0x%02x,)", name, p->VendorID, p->ProductID, p->DeviceProtocol); } if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(VendorID: 0x%04x\n) DEVPATH_FMT(ProductID: 0x%04x\n) DEVPATH_FMT(DeviceClass: 0x%02x(%u)\n) DEVPATH_FMT(DeviceSubClass: 0x%02x(%u)\n) DEVPATH_FMT(DeviceProtocol: 0x%02x(%u)\n), DEVPATH_DAT_HDR(dp), p->VendorID, p->ProductID, p->DeviceClass, p->DeviceClass, p->DeviceSubClass, p->DeviceSubClass, p->DeviceProtocol, p->DeviceProtocol); } } static void devpath_msg_usbwwid(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.7 */ struct { /* Sub-Type 16 */ devpath_t hdr; /* Length = 10 + n */ uint16_t IFaceNum; uint16_t VendorID; uint16_t ProductID; uint8_t SerialNum[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 10); char *serialnum; size_t seriallen; seriallen = p->hdr.Length - offsetof(typeof(*p), SerialNum); if (seriallen == 0) { serialnum = __UNCONST("WWID"); /* XXX: This is an error! */ assert(0); } else { size_t sz = p->hdr.Length - sizeof(*p); serialnum = ucs2_to_utf8((uint16_t *)p->SerialNum, sz, NULL, NULL); } path->sz = easprintf(&path->cp, "UsbWwid(0x%04x,0x%04x,0x%02x,%s)", p->VendorID, p->ProductID, p->IFaceNum, serialnum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(IFaceNum: 0x%04x\n) DEVPATH_FMT(VendorID: 0x%04x\n) DEVPATH_FMT(ProductID: 0x%04x\n) DEVPATH_FMT(SerialNum: %s\n), DEVPATH_DAT_HDR(dp), p->IFaceNum, p->VendorID, p->ProductID, serialnum); } if (seriallen) free(serialnum); } static void devpath_msg_unit(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.8 */ struct { /* Sub-Type 17 */ devpath_t hdr; /* Length = 5 */ uint8_t LUN; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 5); path->sz = easprintf(&path->cp, "Unit(%u)", p->LUN); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(LUN: %u\n), DEVPATH_DAT_HDR(dp), p->LUN); } } static void devpath_msg_sata(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.6 */ struct { /* Sub-Type 18 */ devpath_t hdr; /* Length = 10 */ uint16_t SATAHBAPortNum; uint16_t SATAPortMultiplierPortNum; uint16_t SATALogicalUnitNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 10); path->sz = easprintf(&path->cp, "SATA(%u,%u,%u)", p->SATAHBAPortNum, p->SATAPortMultiplierPortNum, p->SATALogicalUnitNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(SATAHBAPortNum: %u\n) DEVPATH_FMT(SATAPortMultiplierPortNum: %u\n) DEVPATH_FMT(SATALogicalUnitNum: %u\n), DEVPATH_DAT_HDR(dp), p->SATAHBAPortNum, p->SATAPortMultiplierPortNum, p->SATALogicalUnitNum); } } static inline const char * hdrdgst_name(uint16_t LoginOptions) { switch (__SHIFTOUT(LoginOptions, __BITS(1,0))) { case 0: return "None"; case 2: return "CRC32C"; default: return "???"; } } static inline const char * datdgst_name(uint16_t LoginOptions) { switch (__SHIFTOUT(LoginOptions, __BITS(3,2))) { case 0: return "None"; case 2: return "CRC32C"; default: return "???"; } } static inline const char * auth_name(uint16_t LoginOptions) { switch (__SHIFTOUT(LoginOptions, __BITS(12,10))) { case 0: return "CHAP_BI"; case 2: return "None"; case 4: return "CHAP_UNI"; default: return "???"; } } static inline const char * protocol_name(uint16_t Protocol) { return Protocol == 0 ? "TCP" : "RSVD"; } static void devpath_msg_iscsi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.20 */ #define LOGIN_OPTION_BITS \ "\177\020" \ "f\0\2""HdrDgst\0" \ "=\x0""None\0" \ "=\x2""CRC32C\0" \ "f\x2\x2""DatDgst\0" \ "=\x0""None\0" \ "=\x2""CRC32C\0" \ "f\xA\x3""Auth\0" \ "=\x0""CHAP_BI\0" \ "=\x2""None\0" \ "=\x4""CHAP_UNI\0" struct { /* Sub-Type 19 */ devpath_t hdr; /* Length = 18 + n */ uint16_t Protocol; uint16_t LoginOptions; uint64_t LUN; /* display as big-endian */ uint16_t TargetPortalGrp; char TargetName[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 18); char *name; const char *auth, *datdgst, *hdrdgst, *proto; size_t len; /* * Make sure the TargetName is NUL terminated. The spec is * unclear on this, though their example is asciiz. I have * no real examples to test, so be safe. */ len = p->hdr.Length - sizeof(*p); name = emalloc(len + 1); memcpy(name, p->TargetName, len); name[len] = '\0'; auth = auth_name(p->LoginOptions); datdgst = datdgst_name(p->LoginOptions); hdrdgst = hdrdgst_name(p->LoginOptions); proto = protocol_name(p->Protocol); path->sz = easprintf(&path->cp, "iSCSI(%s,0x%04x,0x%064" PRIx64 ",%s,%s,%s,%s)", p->TargetName, p->TargetPortalGrp, htobe64(p->LUN), hdrdgst, datdgst, auth, proto); if (dbg != NULL) { char liopt[256]; snprintb(liopt, sizeof(liopt), LOGIN_OPTION_BITS, p->LoginOptions); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Protocol: 0x%04x(%s)\n) DEVPATH_FMT(LoginOptions: %s\n) DEVPATH_FMT(LUN:) " 0x%064" PRIx64 "\n" DEVPATH_FMT(TargetPortalGrp: 0x%04x\n) DEVPATH_FMT(TargetName: %s\n), DEVPATH_DAT_HDR(dp), p->Protocol, proto, liopt, htobe64(p->LUN), p->TargetPortalGrp, name); } free(name); } static void devpath_msg_vlan(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.13 */ struct { /* Sub-Type 20 */ devpath_t hdr; /* Length = 6 */ uint16_t Vlanid; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 6); path->sz = easprintf(&path->cp, "Vlan(0x%04x)", p->Vlanid); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Vlanid: 0x%04x\n), DEVPATH_DAT_HDR(dp), p->Vlanid); } } static void devpath_msg_fibreex(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.3 */ struct { /* Sub-Type 21 */ devpath_t hdr; /* Length = 24 */ uint32_t Reserved; uint64_t WorldWideName; /* bit-endian */ uint64_t LUN; /* bit-endian */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); path->sz = easprintf(&path->cp, "FibreEx(0x%064" PRIx64 ",0x%064" PRIx64 ")", htobe64(p->WorldWideName), htobe64(p->LUN)); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(WorldWideName:) " 0x%064" PRIx64 "\n" DEVPATH_FMT(LUN:) " 0x%064" PRIx64 "\n", DEVPATH_DAT_HDR(dp), htobe64(p->WorldWideName), htobe64(p->LUN)); } } static void devpath_msg_sasex(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.18 */ struct { /* Sub-Type 22 */ devpath_t hdr; /* Length = 24 XXX: 32 in text */ uint64_t addr; /* display as big-endian */ uint64_t LUN; /* display as big-endian */ union { uint8_t b[2]; uint16_t val; } __packed info; /* device/topology info */ uint16_t RTP; /* Relative Target Port */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 24); /* * XXX: This should match what is in devpath_msg_sas(). * Should we share code? */ if (SASINFO_BYTES(p->info.b[0]) == 0) { path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64 ",0x%064" PRIx64 ")", htobe64(p->addr), htobe64(p->LUN)); } else if (SASINFO_BYTES(p->info.b[0]) == 1) { if (SASINFO_IS_SATA(p->info.b[0])) { path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64 ",0x%064" PRIx64 ",SATA)", htobe64(p->addr), htobe64(p->LUN)); } else { path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64 ",SAS)", htobe64(p->addr)); } } else { assert(SASINFO_BYTES(p->info.b[0]) == 2); uint drivebay = p->info.b[1] + 1; path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64 ",0x%064" PRIx64 ",0x%04x,%s,%s,%s,%d)", htobe64(p->addr), htobe64(p->LUN), p->RTP, SASINFO_SASSATA(p->info.b[0]), SASINFO_EXTERNAL(p->info.b[0]), SASINFO_EXPANDER(p->info.b[0]), drivebay); } if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(addr:) " 0x%064" PRIx64 "(0x%064" PRIx64 ")\n" DEVPATH_FMT(LUN:) " 0x%064" PRIx64 "(0x%064" PRIx64 ")\n" DEVPATH_FMT(info: 0x%02x 0x%02x\n) DEVPATH_FMT(RPT: 0x%04x\n), DEVPATH_DAT_HDR(dp), p->addr, htobe64(p->addr), p->LUN, htobe64(p->LUN), p->info.b[0], p->info.b[1], p->RTP); } } static void devpath_msg_nvme(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.21 */ struct { /* Sub-Type 23 */ devpath_t hdr; /* Length = 16 */ uint32_t NSID; /* Name Space Identifier */ union { uint8_t b[8]; uint64_t val; } EUI; /* IEEE Extended Unique Identifier */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 16); path->sz = easprintf(&path->cp, "NVMe(0x%x," "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X)", p->NSID, p->EUI.b[0], p->EUI.b[1], p->EUI.b[2], p->EUI.b[3], p->EUI.b[4], p->EUI.b[5], p->EUI.b[6], p->EUI.b[7]); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(NSID: 0x%08x\n) DEVPATH_FMT(EUI:) " 0x%016" PRIx64 "\n", DEVPATH_DAT_HDR(dp), p->NSID, p->EUI.val); } } static void devpath_msg_uri(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.22 */ struct { /* Sub-Type 24 */ devpath_t hdr; /* Length = 4 + n */ uint8_t data[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 4); size_t len; char *buf; len = dp->Length - 4; buf = emalloc(len + 1); if (len > 0) memcpy(buf, p->data, len); buf[len] = '\0'; path->sz = easprintf(&path->cp, "Uri(%s)", buf); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(Data: %s\n), DEVPATH_DAT_HDR(dp), buf); } free(buf); } static void devpath_msg_ufs(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.23 */ struct { /* Sub-Type 25 */ devpath_t hdr; /* Length = 6 */ uint8_t PUN; /* Target ID */ uint8_t LUN; /* Logical Unit Number */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 6); path->sz = easprintf(&path->cp, "UFS(%#x,0x%02x)", p->PUN, p->LUN); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(PUN: 0x%02x\n) DEVPATH_FMT(LUN: 0x%02x\n), DEVPATH_DAT_HDR(dp), p->PUN, p->LUN); } } static void devpath_msg_sd(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.24 */ struct { /* Sub-Type 26 */ devpath_t hdr; /* Length = 5 */ uint8_t SlotNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 5); path->sz = easprintf(&path->cp, "SD(%d)", p->SlotNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(SlotNum: 0x%02x\n), DEVPATH_DAT_HDR(dp), p->SlotNum); } } static void devpath_msg_bluetooth(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.25 */ struct { /* Sub-Type 27 */ devpath_t hdr; /* Length = 10 */ uint8_t bdaddr[6]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 10); path->sz = easprintf(&path->cp, "Bluetooth(%02x:%02x:%02x:%02x:%02x:%02x)", p->bdaddr[0], p->bdaddr[1], p->bdaddr[2], p->bdaddr[3], p->bdaddr[4], p->bdaddr[5]); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(bdaddr: 0x%02x%02x%02x%02x%02x%02x\n), DEVPATH_DAT_HDR(dp), p->bdaddr[0], p->bdaddr[1], p->bdaddr[2], p->bdaddr[3], p->bdaddr[4], p->bdaddr[5]); } } static void devpath_msg_wifi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.26 */ struct { /* Sub-Type 28 */ devpath_t hdr; /* Length = 36 */ char SSID[32];/* XXX: ascii? */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 36); path->sz = easprintf(&path->cp, "Wi-Fi(%s)", p->SSID); if (dbg != NULL) { char *ssid; ssid = encode_data((uint8_t *)p->SSID, sizeof(p->SSID)); dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(SSID: %s\n), DEVPATH_DAT_HDR(dp), ssid); free(ssid); } } static void devpath_msg_emmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.27 */ struct { /* Sub-Type 29 */ devpath_t hdr; /* Length = 5 */ uint8_t SlotNum; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 5); path->sz = easprintf(&path->cp, "eMMC(%d)", p->SlotNum); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(SlotNum: 0x%02x\n), DEVPATH_DAT_HDR(dp), p->SlotNum); } } static void devpath_msg_bluetoothle(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.28 */ struct { /* Sub-Type 30 */ devpath_t hdr; /* Length = 11 */ uint8_t bdaddr[6]; uint8_t addr_type; #define BDADDR_TYPE_PUBLIC 0 #define BDADDR_TYPE_RANDOM 1 } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 11); path->sz = easprintf(&path->cp, "BluetoothLE(%02x:%02x:%02x:%02x:%02x:%02x,%d)", p->bdaddr[0], p->bdaddr[1], p->bdaddr[2], p->bdaddr[3], p->bdaddr[4], p->bdaddr[5], p->addr_type); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(bdaddr: 0x%02x%02x%02x%02x%02x%02x\n) DEVPATH_FMT(addr_type: 0x%02x\n), DEVPATH_DAT_HDR(dp), p->bdaddr[0], p->bdaddr[1], p->bdaddr[2], p->bdaddr[3], p->bdaddr[4], p->bdaddr[5], p->addr_type); } } static void devpath_msg_dns(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.29 */ struct { /* Sub-Type 31 */ devpath_t hdr; /* Length = 5 + n */ uint8_t IsIPv6; uint8_t addr[]; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 5); size_t cnt, n, sz; /* XXX: This is ugly at best */ n = p->hdr.Length - sizeof(*p); sz = p->IsIPv6 ? sizeof(struct in6_addr) : sizeof(uint32_t); cnt = n / sz; assert(n == cnt * sz); assert(cnt > 0); if (cnt > 0) { /* XXX: should always be true */ char *bp; #define DNS_PREFIX "Dns(" if (p->IsIPv6) { struct in6_addr *ip6addr = (void *)p->addr; bp = path->cp = malloc(sizeof(DNS_PREFIX) + cnt * INET6_ADDRSTRLEN); bp = stpcpy(bp, DNS_PREFIX); bp = stpcpy(bp, ipv6_addr(&ip6addr[0])); for (size_t i = 1; i < cnt; i++) { *bp++ = ','; bp = stpcpy(bp, ipv6_addr(&ip6addr[i])); } *bp = ')'; } else { /* IPv4 */ uint32_t *ip4addr = (void *)p->addr; bp = path->cp = malloc(sizeof(DNS_PREFIX) + cnt * INET_ADDRSTRLEN); bp = stpcpy(bp, DNS_PREFIX); bp = stpcpy(bp, ipv4_addr(ip4addr[0])); for (size_t i = 1; i < cnt; i++) { *bp++ = ','; bp = stpcpy(bp, ipv4_addr(ip4addr[i])); } *bp = ')'; } #undef DNS_PREFIX path->sz = strlen(bp); } if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(IsIPv6: %d\n), DEVPATH_DAT_HDR(dp), p->IsIPv6); if (cnt > 0) { /* XXX: should always be true */ char *bp, *tp; bp = dbg->cp; if (p->IsIPv6) { struct in6_addr *ip6addr = (void *)p->addr; for (size_t i = 0; i < cnt; i++) { uint8_t *cp; cp = ip6addr[i].__u6_addr.__u6_addr8; tp = bp; dbg->sz += easprintf(&bp, "%s" DEVPATH_FMT(addr[%zu]:) " %02x %02x %02x %02x" " %02x %02x %02x %02x" " %02x %02x %02x %02x" " %02x %02x %02x %02x\n", tp, i, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7], cp[8], cp[9], cp[10], cp[11], cp[12], cp[13], cp[14], cp[15]); free(tp); } } else { /* IPv4 */ uint32_t *ip4addr = (void *)p->addr; for (size_t i = 0; i < cnt; i++) { tp = bp; dbg->sz += easprintf(&bp, "%s" DEVPATH_FMT(addr[i]: 0x%08x\n), tp, ip4addr[i]); free(tp); } } } } } static void devpath_msg_nvdimm(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.30 */ struct { /* Sub-Type 32 */ devpath_t hdr; /* Length = 20 */ uuid_t UUID; } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 20); char uuid_str[UUID_STR_LEN]; uuid_snprintf(uuid_str, sizeof(uuid_str), &p->UUID); path->sz = easprintf(&path->cp, "NVDIMM(%s)", uuid_str); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR, DEVPATH_DAT_HDR(dp) ); } } static void devpath_msg_restservice(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.31 */ struct { /* Sub-Type 33 */ devpath_t hdr; /* Length = 6 */ uint8_t RestService; #define REST_SERVICE_REDFISH 0x01 #define REST_SERVICE_ODATA 0x02 uint8_t AccessMode; #define ACCESS_MODE_IN_BAND 0x01 #define ACCESS_MODE_OUT_OF_BAND 0x02 } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 6); path->sz = easprintf(&path->cp, "RestService(%d,%d)", p->RestService, p->AccessMode); if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(RestService: 0x%02x(%s)\n) DEVPATH_FMT(AccessMode: 0x%02x(%s)\n), DEVPATH_DAT_HDR(dp), p->RestService, p->RestService == REST_SERVICE_REDFISH ? "RedFish" : p->RestService == REST_SERVICE_ODATA ? "OData" : "???", p->AccessMode, p->AccessMode == ACCESS_MODE_IN_BAND ? "In-Band" : p->AccessMode == ACCESS_MODE_OUT_OF_BAND ? "Out-of-Band" : "???"); } } static void devpath_msg_nvmeof(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { /* See 10.3.4.32 */ struct { /* Sub-Type 34 */ devpath_t hdr; /* Length = 21 XXX: 20 in text */ uint8_t NIDT; union { uint64_t dw[2]; uint8_t csi; uint64_t ieuid; uuid_t uuid; } NID; /* big-endian */ uint8_t SubsystemNQN[]; /* UTF-8 null-terminated */ } __packed *p = (void *)dp; __CTASSERT(sizeof(*p) == 21); char uuid_str[UUID_STR_LEN]; /* * See 5.1.13.2.3 of NVM-Express Base Specification Rev 2.1, * in particular, Fig 315 on page 332. */ switch (p->NIDT) { case 0: path->sz = easprintf(&path->cp, "NVMEoF(%s)", p->SubsystemNQN); break; case 1: path->sz = easprintf(&path->cp, "NVMEoF(%s,0x%016" PRIx64 ")", p->SubsystemNQN, p->NID.ieuid); break; case 2: case 3: uuid_snprintf(uuid_str, sizeof(uuid_str), &p->NID.uuid); path->sz = easprintf(&path->cp, "NVMEoF(%s,%s)", p->SubsystemNQN, uuid_str); break; case 4: path->sz = easprintf(&path->cp, "NVMEoF(%s,0x%02x)", p->SubsystemNQN, p->NID.csi); break; default: path->sz = easprintf(&path->cp, "NVMEoF(%s,unknown)", p->SubsystemNQN); break; } if (dbg != NULL) { dbg->sz = easprintf(&dbg->cp, DEVPATH_FMT_HDR DEVPATH_FMT(NIDT: 0x%02x\n) DEVPATH_FMT(NID:) " 0x%016" PRIx64 "%016" PRIx64 "\n" DEVPATH_FMT(SubsystemNQN: '%s'\n), DEVPATH_DAT_HDR(dp), p->NIDT, p->NID.dw[0], p->NID.dw[1], p->SubsystemNQN); } } PUBLIC void devpath_msg(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) { assert(dp->Type = 3); switch (dp->SubType) { case 1: devpath_msg_atapi(dp, path, dbg); return; case 2: devpath_msg_scsi(dp, path, dbg); return; case 3: devpath_msg_fibre(dp, path, dbg); return; case 4: devpath_msg_11394(dp, path, dbg); return; case 5: devpath_msg_usb(dp, path, dbg); return; case 6: devpath_msg_i2o(dp, path, dbg); return; case 9: devpath_msg_infiniband(dp, path, dbg); return; case 10: devpath_msg_vendor(dp, path, dbg); return; case 11: devpath_msg_mac(dp, path, dbg); return; case 12: devpath_msg_ipv4(dp, path, dbg); return; case 13: devpath_msg_ipv6(dp, path, dbg); return; case 14: devpath_msg_uart(dp, path, dbg); return; case 15: devpath_msg_usbclass(dp, path, dbg); return; case 16: devpath_msg_usbwwid(dp, path, dbg); return; case 17: devpath_msg_unit(dp, path, dbg); return; case 18: devpath_msg_sata(dp, path, dbg); return; case 19: devpath_msg_iscsi(dp, path, dbg); return; case 20: devpath_msg_vlan(dp, path, dbg); return; case 21: devpath_msg_fibreex(dp, path, dbg); return; case 22: devpath_msg_sasex(dp, path, dbg); return; case 23: devpath_msg_nvme(dp, path, dbg); return; case 24: devpath_msg_uri(dp, path, dbg); return; case 25: devpath_msg_ufs(dp, path, dbg); return; case 26: devpath_msg_sd(dp, path, dbg); return; case 27: devpath_msg_bluetooth(dp, path, dbg); return; case 28: devpath_msg_wifi(dp, path, dbg); return; case 29: devpath_msg_emmc(dp, path, dbg); return; case 30: devpath_msg_bluetoothle(dp, path, dbg); return; case 31: devpath_msg_dns(dp, path, dbg); return; case 32: devpath_msg_nvdimm(dp, path, dbg); return; case 33: devpath_msg_restservice(dp, path, dbg); return; case 34: devpath_msg_nvmeof(dp, path, dbg); return; default: devpath_unsupported(dp, path, dbg); return; } }