#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: devpath3.c,v 1.7 2025/12/15 17:06:42 joe Exp $");
#endif
#include <arpa/inet.h>
#include <sys/uuid.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <netdb.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
#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
#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)
{
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");
}
}
static void
devpath_msg_atapi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
uint16_t SCSITargetID;
uint16_t SCSILogicalUnitNum;
} __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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
uint32_t Reserved;
uint64_t 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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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);
}
}
static void
devpath_msg_debugport(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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);
}
}
#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)
{
struct {
devpath_t hdr;
uuid_t GUID;
uint32_t resv;
uint64_t addr;
uint64_t LUN;
union {
uint8_t b[2];
uint16_t val;
} __packed info;
uint16_t RTP;
} __packed *p = (void *)dp;
__CTASSERT(sizeof(*p) == 44);
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",
},
{ .GUID = EFI_DEBUGPORT_PROTOCOL_GUID,
.fn = devpath_msg_debugport,
.name = "DebugPort",
},
{ .GUID = DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL,
.fn = devpath_msg_uartflowctl,
.name = "UartFlowCtrl",
},
{ .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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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:
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, <cja015&motorola.com>, 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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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");
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
#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 {
devpath_t hdr;
uint16_t Protocol;
uint16_t LoginOptions;
uint64_t LUN;
uint16_t TargetPortalGrp;
char TargetName[];
} __packed *p = (void *)dp;
__CTASSERT(sizeof(*p) == 18);
char *name;
const char *auth, *datdgst, *hdrdgst, *proto;
size_t len;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
uint32_t Reserved;
uint64_t WorldWideName;
uint64_t LUN;
} __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)
{
struct {
devpath_t hdr;
uint64_t addr;
uint64_t LUN;
union {
uint8_t b[2];
uint16_t val;
} __packed info;
uint16_t RTP;
} __packed *p = (void *)dp;
__CTASSERT(sizeof(*p) == 24);
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)
{
struct {
devpath_t hdr;
uint32_t NSID;
union {
uint8_t b[8];
uint64_t val;
} EUI;
} __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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
uint8_t PUN;
uint8_t LUN;
} __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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
char SSID[32];
} __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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
uint8_t IsIPv6;
uint8_t addr[];
} __packed *p = (void *)dp;
__CTASSERT(sizeof(*p) == 5);
size_t cnt, n, sz;
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) {
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 {
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) {
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 {
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
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)
{
struct {
devpath_t hdr;
uint8_t NIDT;
union {
uint64_t dw[2];
uint8_t csi;
uint64_t ieuid;
uuid_t uuid;
} NID;
uint8_t SubsystemNQN[];
} __packed *p = (void *)dp;
__CTASSERT(sizeof(*p) == 21);
char uuid_str[UUID_STR_LEN];
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;
}
}