Home | History | Annotate | Line # | Download | only in efi
      1 /* $NetBSD: devpath3.c,v 1.6 2025/03/02 01:07:11 riastradh Exp $ */
      2 
      3 /*
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     14  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     23  * SUCH DAMAGE.
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 #ifndef lint
     28 __RCSID("$NetBSD: devpath3.c,v 1.6 2025/03/02 01:07:11 riastradh Exp $");
     29 #endif /* not lint */
     30 
     31 #include <arpa/inet.h>
     32 #include <sys/uuid.h>
     33 
     34 #include <assert.h>
     35 #include <ctype.h>
     36 #include <err.h>
     37 #include <netdb.h>
     38 #include <stddef.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <util.h>
     43 
     44 #include "defs.h"
     45 #include "devpath.h"
     46 #include "devpath3.h"
     47 #include "utils.h"
     48 
     49 #define easprintf	(size_t)easprintf
     50 
     51 #if 0
     52 GUID= EFI_PC_ANSI_GUID
     53 GUID= EFI_VT_100_GIUD
     54 GUID= EFI_VT_100_PLUS_GUID
     55 GUID= EFI_VT_UTF8_GUID
     56 GUID= DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL
     57 GUID= EFI_DEBUGPORT_PROTOCOL_GUID
     58 GUID= d487ddb4-008b-11d9-afdc-001083ffca4d
     59 #endif
     60 
     61 /* Used in sub-type 10 */
     62 #define EFI_PC_ANSI_GUID\
     63   {0xe0c14753,0xf9be,0x11d2,0x9a,0x0c,{0x00,0x90,0x27,0x3f,0xc1,0x4d}}
     64 
     65 #define EFI_VT_100_GUID\
     66   {0xdfa66065,0xb419,0x11d3,0x9a,0x2d,{0x00,0x90,0x27,0x3f,0xc1,0x4d}}
     67 
     68 #define EFI_VT_100_PLUS_GUID\
     69   {0x7baec70b,0x57e0,0x4c76,0x8e,0x87,{0x2f,0x9e,0x28,0x08,0x83,0x43}}
     70 
     71 #define EFI_VT_UTF8_GUID\
     72   {0xad15a0d6,0x8bec,0x4acf,0xa0,0x73,{0xd0,0x1d,0xe7,0x7e,0x2d,0x88}}
     73 
     74 #define EFI_DEBUGPORT_PROTOCOL_GUID \
     75   {0xeba4e8d2,0x3858,0x41ec,0xa2,0x81,{0x26,0x47,0xba,0x96,0x60,0xd0}}
     76 
     77 #define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL \
     78   {0x37499a9d,0x542f,0x4c89,0xa0,0x26,{0x35,0xda,0x14,0x20,0x94,0xe4}}
     79 
     80 #define EFI_VENDOR_SAS\
     81   {0xd487ddb4,0x008b,0x11d9,0xaf,0xdc,{0x00,0x10,0x83,0xff,0xca,0x4d}}
     82 
     83 /************************************************************************/
     84 
     85 static inline char *
     86 upcase(char *str)
     87 {
     88 
     89 	for (char *p = str; *p != '\0'; p++)
     90 		*p = (char)toupper((int)(unsigned char)*p);
     91 	return str;
     92 }
     93 
     94 static inline char *
     95 proto_name(uint16_t proto)	/* See RFC3233/RFC1700 */
     96 {
     97 	struct protoent *ent;
     98 	char *name;
     99 	char *bp;
    100 
    101 	ent = getprotobynumber(proto);
    102 	if (ent == NULL) {
    103 		easprintf(&bp, "0x%04x", proto);
    104 		return bp;
    105 	}
    106 	name = estrdup(ent->p_name);
    107 	return upcase(name);
    108 }
    109 
    110 static inline char *
    111 ipv4_addr(uint32_t addr)
    112 {
    113 	char *bp;
    114 
    115 	bp = ecalloc(1, INET_ADDRSTRLEN);
    116 	if (inet_ntop(AF_INET, &addr, bp, INET_ADDRSTRLEN) == NULL)
    117 		err(EXIT_FAILURE, "%s: inet_ntop(AF_INET)", __func__);
    118 	return bp;
    119 }
    120 
    121 static inline char *
    122 ipv4_type(uint8_t type)
    123 {
    124 
    125 	switch (type) {
    126 	case 0:		return estrdup("DHCP");
    127 	case 1:		return estrdup("Static");
    128 	default:	return estrdup("Unknown");
    129 	}
    130 }
    131 
    132 static inline char *
    133 ipv6_addr(struct in6_addr *addr)
    134 {
    135 	char *bp;
    136 
    137 	bp = ecalloc(1, INET6_ADDRSTRLEN);
    138 	if (inet_ntop(AF_INET6, addr, bp, INET6_ADDRSTRLEN) == NULL)
    139 		err(EXIT_FAILURE, "%s: inet_ntop(AF_INET6)", __func__);
    140 	return bp;
    141 }
    142 
    143 static inline char *
    144 ipv6_type(uint8_t type)
    145 {
    146 
    147 	switch (type) {
    148 	case 0:		return estrdup("Static");
    149 	case 1:		return estrdup("StatelessAutoConfigure");
    150 	case 2:		return estrdup("StatefulAutoConfigure");
    151 	default:	return estrdup("Unknown");
    152 	}
    153 }
    154 
    155 /************************************************************************
    156  * Type 3 - Messaging Device Path
    157  ************************************************************************/
    158 static void
    159 devpath_msg_atapi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    160 {	/* See 10.3.4.1 */
    161 	struct {			/* Sub-Type 1 */
    162 		devpath_t	hdr;	/* Length = 8 */
    163 		uint8_t		IsSecondary;
    164 		uint8_t		IsSlave;
    165 		uint16_t	LUN;
    166 	} __packed *p = (void *)dp;
    167 	__CTASSERT(sizeof(*p) == 8);
    168 
    169 	path->sz = easprintf(&path->cp, "ATAPI(%u,%u,%u)",
    170 	    p->IsSecondary, p->IsSlave, p->LUN);
    171 
    172 	if (dbg != NULL) {
    173 		dbg->sz = easprintf(&dbg->cp,
    174 		    DEVPATH_FMT_HDR
    175 		    DEVPATH_FMT(IsSecondary: %u\n)
    176 		    DEVPATH_FMT(IsPrimary: %u\n)
    177 		    DEVPATH_FMT(LUN: %u\n),
    178 		    DEVPATH_DAT_HDR(dp),
    179 		    p->IsSecondary,
    180 		    p->IsSlave,
    181 		    p->LUN);
    182 	}
    183 }
    184 
    185 static void
    186 devpath_msg_scsi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    187 {	/* See 10.3.4.2 */
    188 	struct {			/* Sub-Type 2 */
    189 		devpath_t	hdr;	/* Length = 8 */
    190 		uint16_t	SCSITargetID;		/* PUN */
    191 		uint16_t	SCSILogicalUnitNum;	/* LUN */
    192 	} __packed *p = (void *)dp;
    193 	__CTASSERT(sizeof(*p) == 8);
    194 
    195 	path->sz = easprintf(&path->cp, "SCSI(%u,%u)",
    196 	    p->SCSITargetID, p->SCSILogicalUnitNum);
    197 
    198 	if (dbg != NULL) {
    199 		dbg->sz = easprintf(&dbg->cp,
    200 		    DEVPATH_FMT_HDR
    201 		    DEVPATH_FMT(SCSITargetID: %u\n)
    202 		    DEVPATH_FMT(SCSILogicalUnitNum: %u\n),
    203 		    DEVPATH_DAT_HDR(dp),
    204 		    p->SCSITargetID,
    205 		    p->SCSILogicalUnitNum);
    206 	}
    207 }
    208 
    209 static void
    210 devpath_msg_fibre(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    211 {	/* See 10.3.4.3 */
    212 	struct {			/* Sub-Type 3 */
    213 		devpath_t	hdr;	/* Length = 24 */
    214 		uint32_t	Reserved;
    215 		uint64_t	WWName;
    216 		uint64_t	LUN;
    217 	} __packed *p = (void *)dp;
    218 	__CTASSERT(sizeof(*p) == 24);
    219 
    220 	path->sz = easprintf(&path->cp, "Fibre(0x%016" PRIx64 ",0x%016"
    221 	    PRIx64 ")", p->WWName, p->LUN);
    222 
    223 	if (dbg != NULL) {
    224 		dbg->sz = easprintf(&dbg->cp,
    225 		    DEVPATH_FMT_HDR
    226 		    DEVPATH_FMT(Reserved: 0x%08x\n)
    227 		    DEVPATH_FMT(WWName:) " 0x%016" PRIx64 "\n"
    228 		    DEVPATH_FMT(LUN:) " 0x%016" PRIx64 "\n",
    229 		    DEVPATH_DAT_HDR(dp),
    230 		    p->Reserved,
    231 		    p->WWName,
    232 		    p->LUN);
    233 	}
    234 }
    235 
    236 static void
    237 devpath_msg_11394(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    238 {	/* See 10.3.4.4 */
    239 	struct {			/* Sub-Type 4 */
    240 		devpath_t	hdr;	/* Length = 16 */
    241 		uint32_t	Reserved;
    242 		uint64_t	GUID;	/* XXX: not an EFI_GUID */
    243 	} __packed *p = (void *)dp;
    244 	__CTASSERT(sizeof(*p) == 16);
    245 
    246 	path->sz = easprintf(&path->cp, "11394(0x%016" PRIx64 ")", p->GUID);
    247 
    248 	if (dbg != NULL) {
    249 		dbg->sz = easprintf(&dbg->cp,
    250 		    DEVPATH_FMT_HDR
    251 		    DEVPATH_FMT(Reserved: 0x%08x\n)
    252 		    DEVPATH_FMT(GUID:) " 0x%016" PRIx64 "\n",
    253 		    DEVPATH_DAT_HDR(dp),
    254 		    p->Reserved,
    255 		    p->GUID);
    256 	}
    257 }
    258 
    259 static void
    260 devpath_msg_usb(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    261 {	/* See 10.3.4.5 */
    262 	struct {			/* Sub-Type 5 */
    263 		devpath_t	hdr;	/* Length = 6 */
    264 		uint8_t		USBParentPortNum;
    265 		uint8_t		USBInterfaceNum;
    266 	} __packed *p = (void *)dp;
    267 	__CTASSERT(sizeof(*p) == 6);
    268 
    269 	path->sz = easprintf(&path->cp, "USB(%u,%u)",
    270 	    p->USBParentPortNum, p->USBInterfaceNum);
    271 
    272 	if (dbg != NULL) {
    273 		dbg->sz = easprintf(&dbg->cp,
    274 		    DEVPATH_FMT_HDR
    275 		    DEVPATH_FMT(USBParentPortNum: %u\n)
    276 		    DEVPATH_FMT(USBInterfaceNum: %u\n),
    277 		    DEVPATH_DAT_HDR(dp),
    278 		    p->USBParentPortNum,
    279 		    p->USBInterfaceNum);
    280 	}
    281 }
    282 
    283 static void
    284 devpath_msg_i2o(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    285 {	/* See 10.3.4.9 */
    286 	struct {			/* Sub-Type 6 */
    287 		devpath_t	hdr;	/* Length = 8 */
    288 		uint32_t	TID;
    289 	} __packed *p = (void *)dp;
    290 	__CTASSERT(sizeof(*p) == 8);
    291 
    292 	path->sz = easprintf(&path->cp, "I2O(0x%08x)", p->TID);
    293 
    294 	if (dbg != NULL) {
    295 		dbg->sz = easprintf(&dbg->cp,
    296 		    DEVPATH_FMT_HDR
    297 		    DEVPATH_FMT(TID: 0x%08x\n),
    298 		    DEVPATH_DAT_HDR(dp),
    299 		    p->TID);
    300 	}
    301 }
    302 
    303 #define INFINIBAND_FLAG_BITS \
    304 	"\177\020"		\
    305 	"b\x0""Service\0"	\
    306 	"b\x1""BootEnv\0"	\
    307 	"b\x2""ConProto\0"	\
    308 	"b\x3""Storage\0"	\
    309 	"b\x4""NetWork\0"	\
    310 	"f\x5\11""Resvd\0"
    311 
    312 static void
    313 devpath_msg_infiniband(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    314 {	/* See 10.3.4.14 */
    315 	struct {			/* Sub-Type 9 */
    316 		devpath_t	hdr;	/* Length = 48 */
    317 		uint32_t	Flags;
    318 		uuid_t		GUID;
    319 		uint64_t	ServiceID;
    320 		uint64_t	PortID;
    321 		uint64_t	DeviceID;
    322 	} __packed *p = (void *)dp;
    323 	__CTASSERT(sizeof(*p) == 48);
    324 	char uuid_str[UUID_STR_LEN];
    325 
    326 	uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    327 
    328 	path->sz = easprintf(&path->cp, "Infiniband(%#x,%s,0x%016" PRIx64
    329 	    ",0x%016" PRIx64 ",0x%016" PRIx64 ")",
    330 	    p->Flags, uuid_str, p->ServiceID, p->PortID, p->DeviceID);
    331 
    332 	if (dbg != NULL) {
    333 		char flags_str[128];
    334 
    335 		snprintb(flags_str, sizeof(flags_str), INFINIBAND_FLAG_BITS,
    336 		    p->Flags);
    337 
    338 		dbg->sz = easprintf(&dbg->cp,
    339 		    DEVPATH_FMT_HDR
    340 		    DEVPATH_FMT(Flags: %s\n)
    341 		    DEVPATH_FMT(GUID: %s\n)
    342 		    DEVPATH_FMT(ServiceID:) " 0x%016" PRIx64 "\n"
    343 		    DEVPATH_FMT(PortID:) " 0x%016" PRIx64 "\n"
    344 		    DEVPATH_FMT(DeviceID:) " 0x%016" PRIx64 "\n",
    345 		    DEVPATH_DAT_HDR(dp),
    346 		    flags_str, uuid_str,
    347 		    p->ServiceID, p->PortID, p->DeviceID);
    348 	}
    349 }
    350 
    351 /****************************************
    352  * Sub-Type 10 variants
    353  */
    354 static void
    355 devpath_msg_debugport(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    356 {	/* See 18.3.7 */
    357 	struct {			/* Sub-Type 10 */
    358 		devpath_t	hdr;	/* Length = 20 */
    359 		uuid_t		GUID;
    360 	} __packed *p = (void *)dp;
    361 	__CTASSERT(sizeof(*p) == 20);
    362 
    363 	path->sz = easprintf(&path->cp, "DebugPort()");
    364 
    365 	if (dbg != NULL) {
    366 		char uuid_str[UUID_STR_LEN];
    367 
    368 		uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    369 
    370 		dbg->sz = easprintf(&dbg->cp,
    371 		    DEVPATH_FMT_HDR
    372 		    DEVPATH_FMT(GUID: %s\n),
    373 		    DEVPATH_DAT_HDR(dp),
    374 		    uuid_str);
    375 	}
    376 }
    377 
    378 static void
    379 devpath_msg_uartflowctl(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    380 {	/* See 10.3.4.17 */
    381 	struct {			/* Sub-Type 10 */
    382 		devpath_t	hdr;	/* Length = 24 */
    383 		uuid_t		GUID;
    384 		uint32_t	FlowCtl;
    385 	} __packed *p = (void *)dp;
    386 	__CTASSERT(sizeof(*p) == 24);
    387 	const char *fc_str;
    388 
    389 	switch (p->FlowCtl) {
    390 	case 0:		fc_str = "None";	break;
    391 	case 1:		fc_str = "Hardware";	break;
    392 	case 2:		fc_str = "XonXoff";	break;
    393 	default:	fc_str = "????";	break;
    394 	}
    395 
    396 	path->sz = easprintf(&path->cp, "UartFlowCtrl(%s)", fc_str);
    397 
    398 	if (dbg != NULL) {
    399 		char uuid_str[UUID_STR_LEN];
    400 
    401 		uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    402 
    403 		dbg->sz = easprintf(&dbg->cp,
    404 		    DEVPATH_FMT_HDR
    405 		    DEVPATH_FMT(GUID: %s\n)
    406 		    DEVPATH_FMT(FlowCtl: 0x%04x(%s)\n),
    407 		    DEVPATH_DAT_HDR(dp),
    408 		    uuid_str,
    409 		    p->FlowCtl, fc_str);
    410 	}
    411 }
    412 
    413 /****************************************
    414  * Macros for dealing with SAS/SATA device and topology info field.
    415  */
    416 
    417 #define SASINFO_BYTES_MASK	__BITS(3,0)
    418 #define SASINFO_SATA_BIT	__BIT(4)
    419 #define SASINFO_EXTERNAL_BIT	__BIT(5)
    420 #define SASINFO_EXPANDER_BIT	__BIT(6)
    421 
    422 #define SASINFO_BYTES(b)	__SHIFTOUT((b), SASINFO_BYTES_MASK)
    423 #define SASINFO_IS_SATA(b)	((b) % SASINFO_SATA_BIT)
    424 #define SASINFO_IS_EXTERNAL(b)	((b) % SASINFO_EXTERNAL_BIT)
    425 #define SASINFO_IS_EXPANDER(b)	((b) % SASINFO_EXPANDER_BIT)
    426 
    427 #define SASINFO_SASSATA(b)  (SASINFO_IS_SATA(b)     ? "SATA"     : "SAS")
    428 #define SASINFO_EXTERNAL(b) (SASINFO_IS_EXTERNAL(b) ? "External" : "Internal")
    429 #define SASINFO_EXPANDER(b) (SASINFO_IS_EXPANDER(b) ? "Expander" : "direct")
    430 
    431 /****************************************/
    432 
    433 static void
    434 devpath_msg_sas(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    435 {	/* See 10.3.4.18 */
    436 	struct {			/* Sub-Type 10 */
    437 		devpath_t	hdr;	/* Length = 44 */
    438 		uuid_t		GUID;
    439 		uint32_t	resv;
    440 		uint64_t	addr;	/* display as big-endian */
    441 		uint64_t	LUN;	/* display as big-endian */
    442 		union {
    443 			uint8_t b[2];
    444 			uint16_t val;
    445 		} __packed info;	/* device/topology info */
    446 		uint16_t	RTP;	/* Relative Target Port */
    447 	} __packed *p = (void *)dp;
    448 	__CTASSERT(sizeof(*p) == 44);
    449 
    450 	/*
    451 	 * There seems to be a discrepency between the display
    452 	 * examples in 10.3.4.18, 10.3.4.18.4, and Table 10.67.  The
    453 	 * first example in 10.3.4.18 also refers to a third number
    454 	 * (RTP) which isn't present.  I also find the info in Table
    455 	 * 10.67 a bit unclear.
    456 	 */
    457 	if (SASINFO_BYTES(p->info.b[0]) == 0) {
    458 		path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64
    459 		    ",0x%064" PRIx64 ")",
    460 		    htobe64(p->addr), htobe64(p->LUN));
    461 	}
    462 	else if (SASINFO_BYTES(p->info.b[0]) == 1) {
    463 		if (SASINFO_IS_SATA(p->info.b[0])) {
    464 			path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64
    465 			    ",0x%064" PRIx64 ",SATA)",
    466 			    htobe64(p->addr), htobe64(p->LUN));
    467 		}
    468 		else {
    469 			path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64
    470 			    ",SAS)", htobe64(p->addr));
    471 		}
    472 	}
    473 	else {
    474 		assert(SASINFO_BYTES(p->info.b[0]) == 2);
    475 		uint drivebay = p->info.b[1] + 1;
    476 		path->sz = easprintf(&path->cp, "SAS(0x%064" PRIx64
    477 		    ",0x%064" PRIx64 ",0x%04x,%s,%s,%s,%d,0x%04x)",
    478 		    htobe64(p->addr), htobe64(p->LUN), p->RTP,
    479 		    SASINFO_SASSATA(p->info.b[0]),
    480 		    SASINFO_EXTERNAL(p->info.b[0]),
    481 		    SASINFO_EXPANDER(p->info.b[0]),
    482 		    drivebay,
    483 		    p->resv);
    484 	}
    485 
    486 	if (dbg != NULL) {
    487 		char uuid_str[UUID_STR_LEN];
    488 
    489 		uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    490 
    491 		dbg->sz = easprintf(&dbg->cp,
    492 		    DEVPATH_FMT_HDR
    493 		    DEVPATH_FMT(GUID: %s\n)
    494 		    DEVPATH_FMT(resv: 0x%08x\n)
    495 		    DEVPATH_FMT(addr:) " 0x%064" PRIx64 "(0x%064" PRIx64 ")\n"
    496 		    DEVPATH_FMT(LUN:) "  0x%064" PRIx64 "(0x%064" PRIx64 ")\n"
    497 		    DEVPATH_FMT(info: 0x%02x 0x%02x\n)
    498 		    DEVPATH_FMT(RPT:  0x%04x\n),
    499 		    DEVPATH_DAT_HDR(dp),
    500 		    uuid_str,
    501 		    p->resv,
    502 		    p->addr, htobe64(p->addr),
    503 		    p->LUN,  htobe64(p->LUN),
    504 		    p->info.b[0], p->info.b[1],
    505 		    p->RTP);
    506 	}
    507 }
    508 
    509 static struct vendor_type {
    510 	uuid_t GUID;
    511 	void(*fn)(devpath_t *, devpath_elm_t *, devpath_elm_t *);
    512 	const char *name;
    513 } *
    514 devpath_msg_vendor_type(uuid_t *uuid)
    515 {
    516 	static struct vendor_type tbl[] = {
    517 		{ .GUID = EFI_PC_ANSI_GUID,
    518 		  .fn   = NULL,
    519 		  .name = "VenPcAnsi",
    520 		},
    521 		{ .GUID = EFI_VT_100_GUID,
    522 		  .fn   = NULL,
    523 		  .name = "VenVt100",
    524 		},
    525 		{ .GUID = EFI_VT_100_PLUS_GUID,
    526 		  .fn   = NULL,
    527 		  .name = "VenVt100Plus",
    528 		},
    529 		{ .GUID = EFI_VT_UTF8_GUID,
    530 		  .fn   = NULL,
    531 		  .name = "VenUtf8",
    532 		},
    533 		/********/
    534 		/* See 18.3.7 */
    535 		{ .GUID = EFI_DEBUGPORT_PROTOCOL_GUID,
    536 		  .fn   = devpath_msg_debugport,
    537 		  .name = "DebugPort",
    538 		},
    539 		/********/
    540 		/* See 10.3.4.17 */
    541 		{ .GUID = DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL,
    542 		  .fn   = devpath_msg_uartflowctl,
    543 		  .name = "UartFlowCtrl",
    544 		},
    545 		/* See 10.3.4.18 */
    546 		{ .GUID = EFI_VENDOR_SAS,
    547 		  .fn   = devpath_msg_sas,
    548 		  .name = "SAS",
    549 		},
    550 	};
    551 
    552 	for (size_t i = 0; i < __arraycount(tbl); i++) {
    553 		if (memcmp(uuid, &tbl[i].GUID, sizeof(*uuid)) == 0) {
    554 			return &tbl[i];
    555 		}
    556 	}
    557 	return NULL;
    558 }
    559 
    560 static void
    561 devpath_msg_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    562 {	/* See 10.3.4.16 */
    563 	struct {			/* Sub-Type 10 */
    564 		devpath_t	hdr;	/* Length = 20 + n */
    565 		uuid_t		GUID;
    566 		uint8_t		data[];
    567 	} __packed *p = (void *)dp;
    568 	__CTASSERT(sizeof(*p) == 20);
    569 	char uuid_str[UUID_STR_LEN];
    570 	size_t len;
    571 	struct vendor_type *vt;
    572 	char *data_str;
    573 
    574 	uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
    575 
    576 	len = dp->Length - sizeof(*p);
    577 	data_str = encode_data(p->data, len);
    578 
    579 	vt = devpath_msg_vendor_type(&p->GUID);
    580 	if (vt == NULL) {
    581 		path->sz = easprintf(&path->cp, "VenMsg(%s,%s)",
    582 		    uuid_str, data_str);
    583 	}
    584 	else if (vt->fn == NULL) {
    585 		assert(vt->name != NULL);
    586 		path->sz = easprintf(&path->cp, "%s(%s)", vt->name, data_str);
    587 	}
    588 	else {
    589 		vt->fn(dp, path, dbg);
    590 		return;
    591 	}
    592 	if (dbg != NULL) {
    593 		dbg->sz = easprintf(&dbg->cp,
    594 		    DEVPATH_FMT_HDR
    595 		    DEVPATH_FMT(GUID: %s\n)
    596 		    DEVPATH_FMT(Data: %s\n),
    597 		    DEVPATH_DAT_HDR(dp),
    598 		    uuid_str,
    599 		    data_str);
    600 	}
    601 	free(data_str);
    602 }
    603 
    604 static void
    605 devpath_msg_mac(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    606 {	/* See 10.3.4.10 */
    607 	struct {			/* Sub-Type 11 */
    608 		devpath_t	hdr;	/* Length = 37 */
    609 		uint8_t		mac_addr[32];
    610 		uint8_t		IfType;
    611 	} __packed *p = (void *)dp;
    612 	__CTASSERT(sizeof(*p) == 37);
    613 	size_t addr_len;
    614 	char *mac_addr;
    615 
    616 	switch (p->IfType) {
    617 	case 0:
    618 	case 1:
    619 		addr_len = 6;
    620 		break;
    621 	default:
    622 		addr_len = 32;
    623 		break;
    624 	}
    625 #if 0
    626  From: RFC3232 says everything is now online, found here:
    627  https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
    628 
    629 XXX: Should we make a table so we can show a name?
    630 
    631     0  Reserved [RFC5494]
    632     1  Ethernet (10Mb) [Jon_Postel]
    633     2  Experimental Ethernet (3Mb) [Jon_Postel]
    634     3  Amateur Radio AX.25 [Philip_Koch]
    635     4  Proteon ProNET Token Ring [Avri_Doria]
    636     5  Chaos [Gill_Pratt]
    637     6  IEEE 802 Networks [Jon_Postel]
    638     7  ARCNET [RFC1201]
    639     8  Hyperchannel [Jon_Postel]
    640     9  Lanstar [Tom_Unger]
    641     10 Autonet Short Address [Mike_Burrows]
    642     11 LocalTalk [Joyce_K_Reynolds]
    643     12 LocalNet (IBM PCNet or SYTEK LocalNET) [Joseph Murdock]
    644     13 Ultra link [Rajiv_Dhingra]
    645     14 SMDS [George_Clapp]
    646     15 Frame Relay [Andy_Malis]
    647     16 Asynchronous Transmission Mode (ATM) [[JXB2]]
    648     17 HDLC [Jon_Postel]
    649     18 Fibre Channel [RFC4338]
    650     19 Asynchronous Transmission Mode (ATM) [RFC2225]
    651     20 Serial Line [Jon_Postel]
    652     21 Asynchronous Transmission Mode (ATM) [Mike_Burrows]
    653     22 MIL-STD-188-220 [Herb_Jensen]
    654     23 Metricom [Jonathan_Stone]
    655     24 IEEE 1394.1995 [Myron_Hattig]
    656     25 MAPOS [Mitsuru_Maruyama][RFC2176]
    657     26 Twinaxial [Marion_Pitts]
    658     27 EUI-64 [Kenji_Fujisawa]
    659     28 HIPARP [Jean_Michel_Pittet]
    660     29 IP and ARP over ISO 7816-3 [Scott_Guthery]
    661     30 ARPSec [Jerome_Etienne]
    662     31 IPsec tunnel [RFC3456]
    663     32 InfiniBand (TM) [RFC4391]
    664     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]
    665     34 Wiegand Interface [Scott_Guthery_2]
    666     35 Pure IP [Inaky_Perez-Gonzalez]
    667     36 HW_EXP1 [RFC5494]
    668     37 HFI [Tseng-Hui_Lin]
    669     38 Unified Bus (UB) [Wei_Pan]
    670     39-255 Unassigned
    671     256 HW_EXP2 [RFC5494]
    672     257 AEthernet [Geoffroy_Gramaize]
    673     258-65534 Unassigned
    674     65535 Reserved [RFC5494]
    675 #endif
    676 
    677 	mac_addr = encode_data(p->mac_addr, addr_len);
    678 	path->sz = easprintf(&path->cp, "MAC(%s,%d)", mac_addr, p->IfType);
    679 
    680 	if (dbg != NULL) {
    681 		dbg->sz = easprintf(&dbg->cp,
    682 		    DEVPATH_FMT_HDR
    683 		    DEVPATH_FMT(MAC_addr: %s\n)
    684 		    DEVPATH_FMT(IfType: %x\n),
    685 		    DEVPATH_DAT_HDR(dp),
    686 		    mac_addr,
    687 		    p->IfType);
    688 	}
    689 	free(mac_addr);
    690 }
    691 
    692 static void
    693 devpath_msg_ipv4(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    694 {	/* See 10.3.4.11 */
    695 	struct {			/* Sub-Type 12 */
    696 		devpath_t	hdr;	/* Length = 27 */
    697 		uint32_t	LocalIPAddr;
    698 		uint32_t	RemoteIPAddr;
    699 		uint16_t	LocalPort;
    700 		uint16_t	RemotePort;
    701 		uint16_t	Protocol;
    702 		uint8_t		StaticIPAddr;
    703 		uint32_t	GatewayIPAddr;
    704 		uint32_t	SubnetMask;
    705 	} __packed *p = (void *)dp;
    706 	__CTASSERT(sizeof(*p) == 27);
    707 	char *gaddr, *laddr, *raddr, *mask;
    708 	char *proto, *atype;
    709 
    710 	laddr = ipv4_addr(p->LocalIPAddr);
    711 	gaddr = ipv4_addr(p->GatewayIPAddr);
    712 	raddr = ipv4_addr(p->RemoteIPAddr);
    713 	mask  = ipv4_addr(p->SubnetMask);
    714 	proto = proto_name(p->Protocol);
    715 	atype = ipv4_type(p->StaticIPAddr);
    716 
    717 	path->sz = easprintf(&path->cp, "IPv4(%s,%s,%s,%s,%s,%s)",
    718 	    raddr, proto, atype, laddr, gaddr, mask);
    719 
    720 	if (dbg != NULL) {
    721 		dbg->sz = easprintf(&dbg->cp,
    722 		    DEVPATH_FMT_HDR
    723 		    DEVPATH_FMT(LocalIPAddr: 0x%08x(%s)\n)
    724 		    DEVPATH_FMT(RemoteIPAddr: 0x%08x(%s)\n)
    725 		    DEVPATH_FMT(LocalPort: 0x%04x\n)
    726 		    DEVPATH_FMT(RemotePort: 0x%04x\n)
    727 		    DEVPATH_FMT(Protocol: 0x%04x(%s)\n)
    728 		    DEVPATH_FMT(StaticIPAddr: 0x%02x(%s)\n)
    729 		    DEVPATH_FMT(GatewayIPAddr: 0x%08x(%s)\n)
    730 		    DEVPATH_FMT(SubnetMask: 0x%08x(%s)\n),
    731 		    DEVPATH_DAT_HDR(dp),
    732 		    p->LocalIPAddr, laddr,
    733 		    p->RemoteIPAddr, raddr,
    734 		    p->LocalPort,
    735 		    p->RemotePort,
    736 		    p->Protocol, proto,
    737 		    p->StaticIPAddr, atype,
    738 		    p->GatewayIPAddr, gaddr,
    739 		    p->SubnetMask, mask);
    740 	}
    741 	free(atype);
    742 	free(proto);
    743 	free(mask);
    744 	free(raddr);
    745 	free(gaddr);
    746 	free(laddr);
    747 }
    748 
    749 static void
    750 devpath_msg_ipv6(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    751 {	/* See 10.3.4.12 */
    752 	struct {			/* Sub-Type 13 */
    753 		devpath_t	hdr;	/* Length = 60 */
    754 		struct in6_addr	LocalIPAddr;
    755 		struct in6_addr	RemoteIPAddr;
    756 		uint16_t	LocalPort;
    757 		uint16_t	RemotePort;
    758 		uint16_t	Protocol;
    759 		uint8_t		IPAddrOrigin;
    760 		uint8_t		PrefixLength;
    761 		struct in6_addr	GatewayIPAddr;
    762 	} __packed *p = (void *)dp;
    763 	__CTASSERT(sizeof(*p) == 60);
    764 	char *gaddr, *laddr, *raddr;
    765 	char *proto, *atype;
    766 
    767 	laddr = ipv6_addr(&p->LocalIPAddr);
    768 	gaddr = ipv6_addr(&p->GatewayIPAddr);
    769 	raddr = ipv6_addr(&p->RemoteIPAddr);
    770 	proto = proto_name(p->Protocol);
    771 	atype = ipv6_type(p->IPAddrOrigin);
    772 
    773 	path->sz = easprintf(&path->cp, "IPv6(%s,%s,%s,%s,%s)",
    774 	    raddr, proto, atype, laddr, gaddr);
    775 
    776 	if (dbg != NULL) {
    777 		dbg->sz = easprintf(&dbg->cp,
    778 		    DEVPATH_FMT_HDR
    779 		    DEVPATH_FMT(LocalIPAddr: %s\n)
    780 		    DEVPATH_FMT(RemoteIPAddr: %s\n)
    781 		    DEVPATH_FMT(LocalPort: 0x%04x\n)
    782 		    DEVPATH_FMT(RemotePort: 0x%04x\n)
    783 		    DEVPATH_FMT(Protocol: 0x%04x(%s)\n)
    784 		    DEVPATH_FMT(IPAddrOrigin: 0x%02x(%s)\n)
    785 		    DEVPATH_FMT(PrefixLength: 0x%02x\n)
    786 		    DEVPATH_FMT(GatewayIPAddr: %s\n),
    787 		    DEVPATH_DAT_HDR(dp),
    788 		    laddr,
    789 		    raddr,
    790 		    p->LocalPort,
    791 		    p->RemotePort,
    792 		    p->Protocol, proto,
    793 		    p->IPAddrOrigin, atype,
    794 		    p->PrefixLength,
    795 		    gaddr);
    796 	}
    797 	free(atype);
    798 	free(proto);
    799 	free(raddr);
    800 	free(gaddr);
    801 	free(laddr);
    802 }
    803 
    804 static inline const char *
    805 uart_parity(uint8_t n)
    806 {
    807 
    808 	switch (n) {
    809 	case 0:		return "D";
    810 	case 1:		return "N";
    811 	case 2:		return "E";
    812 	case 3:		return "O";
    813 	case 4:		return "M";
    814 	case 5:		return "S";
    815 	default:	return "?";
    816 	}
    817 }
    818 
    819 static inline const char *
    820 uart_stopbits(uint8_t n)
    821 {
    822 
    823 	switch (n) {
    824 	case 0:		return "D";
    825 	case 1:		return "1";
    826 	case 2:		return "1.5";
    827 	case 3:		return "2";
    828 	default:	return "?";
    829 	}
    830 }
    831 
    832 static void
    833 devpath_msg_uart(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    834 {	/* See 10.3.4.15 */
    835 	struct {			/* Sub-Type 14 */
    836 		devpath_t	hdr;	/* Length = 19 */
    837 		uint32_t	Reserved;
    838 		uint64_t	BaudRate;
    839 		uint8_t		DataBits;
    840 		uint8_t		Parity;
    841 		uint8_t		StopBits;
    842 	} __packed *p = (void *)dp;
    843 	__CTASSERT(sizeof(*p) == 19);
    844 	const char *parity, *stopbits;
    845 
    846 	parity = uart_parity(p->Parity);
    847 	stopbits = uart_stopbits(p->StopBits);
    848 
    849 	path->sz = easprintf(&path->cp, "Uart(%" PRIx64 ",%u,%s,%s)",
    850 	    p->BaudRate, p->DataBits, parity, stopbits);
    851 
    852 	if (dbg != NULL) {
    853 		dbg->sz = easprintf(&dbg->cp,
    854 		    DEVPATH_FMT_HDR
    855 		    DEVPATH_FMT(Reserved: 0x%08x\n)
    856 		    DEVPATH_FMT(BaudRate:) " 0x%016" PRIx64 "\n"
    857 		    DEVPATH_FMT(DataBits: 0x%1x\n)
    858 		    DEVPATH_FMT(Parity:   0x%1x(%s)\n)
    859 		    DEVPATH_FMT(StopBits: 0x%1x(%s)\n),
    860 		    DEVPATH_DAT_HDR(dp),
    861 		    p->Reserved,
    862 		    p->BaudRate,
    863 		    p->DataBits,
    864 		    p->Parity, parity,
    865 		    p->StopBits, stopbits);
    866 	}
    867 }
    868 
    869 static inline const char *
    870 usbclass_name(uint8_t class, uint8_t subclass)
    871 {
    872 
    873 	switch (class) {
    874 	case 1:		return "UsbAudio";
    875 	case 2:		return "UsbCDCControl";
    876 	case 3:		return "UsbHID";
    877 	case 6:		return "UsbImage";
    878 	case 7:		return "UsbPrintr";
    879 	case 8:		return "UsbMassStorage";
    880 	case 9:		return "UsbHub";
    881 	case 10:	return "UsbCDCData";
    882 	case 11:	return "UsbSmartCard";
    883 	case 14:	return "UsbVideo";
    884 	case 220:	return "UsbDiagnostic";
    885 	case 224:	return "UsbWireless";
    886 	case 254:
    887 		switch (subclass) {
    888 		case 1:		return "UsbDeviceFirmwareUpdate";
    889 		case 2:		return "UsbIrdaBridge";
    890 		case 3:		return "UsbTestAndMeasurement";
    891 		default:	return NULL;
    892 		}
    893 	default:	return NULL;
    894 	}
    895 }
    896 
    897 static void
    898 devpath_msg_usbclass(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    899 {	/* See 10.3.4.8 */
    900 	struct {			/* Sub-Type 15 */
    901 		devpath_t	hdr;	/* Length = 11 */
    902 		uint16_t	VendorID;
    903 		uint16_t	ProductID;
    904 		uint8_t		DeviceClass;
    905 		uint8_t		DeviceSubClass;
    906 		uint8_t		DeviceProtocol;
    907 	} __packed *p = (void *)dp;
    908 	__CTASSERT(sizeof(*p) == 11);
    909 	const char *name;
    910 
    911 	name = usbclass_name(p->DeviceClass, p->DeviceSubClass);
    912 	if (name == NULL) {
    913 		path->sz = easprintf(&path->cp,
    914 		    "UsbClass(0x%04x,0x%04x,0x%02x,0x%02x,0x%02x,)",
    915 		    p->VendorID, p->ProductID, p->DeviceClass,
    916 		    p->DeviceSubClass, p->DeviceProtocol);
    917 	}
    918 	else if (p->DeviceClass != 254) {
    919 		path->sz = easprintf(&path->cp,
    920 		    "%s(0x%04x,0x%04x,0x%02x,0x%02x,)",
    921 		    name, p->VendorID, p->ProductID, p->DeviceSubClass,
    922 		    p->DeviceProtocol);
    923 	}
    924 	else {
    925 		path->sz = easprintf(&path->cp, "%s(0x%04x,0x%04x,0x%02x,)",
    926 		    name, p->VendorID, p->ProductID, p->DeviceProtocol);
    927 	}
    928 
    929 	if (dbg != NULL) {
    930 		dbg->sz = easprintf(&dbg->cp,
    931 		    DEVPATH_FMT_HDR
    932 		    DEVPATH_FMT(VendorID:  0x%04x\n)
    933 		    DEVPATH_FMT(ProductID: 0x%04x\n)
    934 		    DEVPATH_FMT(DeviceClass: 0x%02x(%u)\n)
    935 		    DEVPATH_FMT(DeviceSubClass: 0x%02x(%u)\n)
    936 		    DEVPATH_FMT(DeviceProtocol: 0x%02x(%u)\n),
    937 		    DEVPATH_DAT_HDR(dp),
    938 		    p->VendorID,
    939 		    p->ProductID,
    940 		    p->DeviceClass, p->DeviceClass,
    941 		    p->DeviceSubClass, p->DeviceSubClass,
    942 		    p->DeviceProtocol, p->DeviceProtocol);
    943 	}
    944 }
    945 
    946 static void
    947 devpath_msg_usbwwid(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    948 {	/* See 10.3.4.7 */
    949 	struct {			/* Sub-Type 16 */
    950 		devpath_t	hdr;	/* Length = 10 + n */
    951 		uint16_t	IFaceNum;
    952 		uint16_t	VendorID;
    953 		uint16_t	ProductID;
    954 		uint8_t		SerialNum[];
    955 	} __packed *p = (void *)dp;
    956 	__CTASSERT(sizeof(*p) == 10);
    957 	char *serialnum;
    958 	size_t seriallen;
    959 
    960 	seriallen = p->hdr.Length - offsetof(typeof(*p), SerialNum);
    961 	if (seriallen == 0) {
    962 		serialnum = __UNCONST("WWID");	/* XXX: This is an error! */
    963 		assert(0);
    964 	}
    965 	else {
    966 		size_t sz = p->hdr.Length - sizeof(*p);
    967 		serialnum = ucs2_to_utf8((uint16_t *)p->SerialNum, sz, NULL,
    968 		    NULL);
    969 	}
    970 
    971 	path->sz = easprintf(&path->cp, "UsbWwid(0x%04x,0x%04x,0x%02x,%s)",
    972 	    p->VendorID, p->ProductID, p->IFaceNum, serialnum);
    973 
    974 	if (dbg != NULL) {
    975 		dbg->sz = easprintf(&dbg->cp,
    976 		    DEVPATH_FMT_HDR
    977 		    DEVPATH_FMT(IFaceNum: 0x%04x\n)
    978 		    DEVPATH_FMT(VendorID: 0x%04x\n)
    979 		    DEVPATH_FMT(ProductID: 0x%04x\n)
    980 		    DEVPATH_FMT(SerialNum: %s\n),
    981 		    DEVPATH_DAT_HDR(dp),
    982 		    p->IFaceNum, p->VendorID, p->ProductID, serialnum);
    983 	}
    984 
    985 	if (seriallen)
    986 		free(serialnum);
    987 }
    988 
    989 static void
    990 devpath_msg_unit(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
    991 {	/* See 10.3.4.8 */
    992 	struct {			/* Sub-Type 17 */
    993 		devpath_t	hdr;	/* Length = 5 */
    994 		uint8_t		LUN;
    995 	} __packed *p = (void *)dp;
    996 	__CTASSERT(sizeof(*p) == 5);
    997 
    998 	path->sz = easprintf(&path->cp, "Unit(%u)", p->LUN);
    999 
   1000 	if (dbg != NULL) {
   1001 		dbg->sz = easprintf(&dbg->cp,
   1002 		    DEVPATH_FMT_HDR
   1003 		    DEVPATH_FMT(LUN: %u\n),
   1004 		    DEVPATH_DAT_HDR(dp),
   1005 		    p->LUN);
   1006 	}
   1007 }
   1008 
   1009 static void
   1010 devpath_msg_sata(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1011 {	/* See 10.3.4.6 */
   1012 	struct {			/* Sub-Type 18 */
   1013 		devpath_t	hdr;	/* Length = 10 */
   1014 		uint16_t	SATAHBAPortNum;
   1015 		uint16_t	SATAPortMultiplierPortNum;
   1016 		uint16_t	SATALogicalUnitNum;
   1017 	} __packed *p = (void *)dp;
   1018 	__CTASSERT(sizeof(*p) == 10);
   1019 
   1020 	path->sz = easprintf(&path->cp, "SATA(%u,%u,%u)", p->SATAHBAPortNum,
   1021 	    p->SATAPortMultiplierPortNum, p->SATALogicalUnitNum);
   1022 
   1023 	if (dbg != NULL) {
   1024 		dbg->sz = easprintf(&dbg->cp,
   1025 		    DEVPATH_FMT_HDR
   1026 		    DEVPATH_FMT(SATAHBAPortNum: %u\n)
   1027 		    DEVPATH_FMT(SATAPortMultiplierPortNum: %u\n)
   1028 		    DEVPATH_FMT(SATALogicalUnitNum: %u\n),
   1029 		    DEVPATH_DAT_HDR(dp),
   1030 		    p->SATAHBAPortNum,
   1031 		    p->SATAPortMultiplierPortNum,
   1032 		    p->SATALogicalUnitNum);
   1033 	}
   1034 }
   1035 
   1036 static inline const char *
   1037 hdrdgst_name(uint16_t LoginOptions)
   1038 {
   1039 
   1040 	switch (__SHIFTOUT(LoginOptions, __BITS(1,0))) {
   1041 	case 0:		return "None";
   1042 	case 2:		return "CRC32C";
   1043 	default: 	return "???";
   1044 	}
   1045 }
   1046 
   1047 static inline const char *
   1048 datdgst_name(uint16_t LoginOptions)
   1049 {
   1050 
   1051 	switch (__SHIFTOUT(LoginOptions, __BITS(3,2))) {
   1052 	case 0:		return "None";
   1053 	case 2:		return "CRC32C";
   1054 	default: 	return "???";
   1055 	}
   1056 }
   1057 
   1058 static inline const char *
   1059 auth_name(uint16_t LoginOptions)
   1060 {
   1061 
   1062 	switch (__SHIFTOUT(LoginOptions, __BITS(12,10))) {
   1063 	case 0:		return "CHAP_BI";
   1064 	case 2:		return "None";
   1065 	case 4:		return "CHAP_UNI";
   1066 	default:	return "???";
   1067 	}
   1068 }
   1069 
   1070 static inline const char *
   1071 protocol_name(uint16_t Protocol)
   1072 {
   1073 
   1074 	return Protocol == 0 ? "TCP" : "RSVD";
   1075 }
   1076 
   1077 static void
   1078 devpath_msg_iscsi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1079 {	/* See 10.3.4.20 */
   1080 #define LOGIN_OPTION_BITS \
   1081 	"\177\020"		\
   1082 	"f\0\2""HdrDgst\0"	\
   1083 	"=\x0""None\0"		\
   1084 	"=\x2""CRC32C\0"	\
   1085 	"f\x2\x2""DatDgst\0"	\
   1086 	"=\x0""None\0"		\
   1087 	"=\x2""CRC32C\0"	\
   1088 	"f\xA\x3""Auth\0"	\
   1089 	"=\x0""CHAP_BI\0"	\
   1090 	"=\x2""None\0"		\
   1091 	"=\x4""CHAP_UNI\0"
   1092 	struct {			/* Sub-Type 19 */
   1093 		devpath_t	hdr;	/* Length = 18 + n */
   1094 		uint16_t	Protocol;
   1095 		uint16_t	LoginOptions;
   1096 		uint64_t	LUN;	/* display as big-endian */
   1097 		uint16_t	TargetPortalGrp;
   1098 		char 		TargetName[];
   1099 	} __packed *p = (void *)dp;
   1100 	__CTASSERT(sizeof(*p) == 18);
   1101 	char *name;
   1102 	const char *auth, *datdgst, *hdrdgst, *proto;
   1103 	size_t len;
   1104 
   1105 	/*
   1106 	 * Make sure the TargetName is NUL terminated.  The spec is
   1107 	 * unclear on this, though their example is asciiz.  I have
   1108 	 * no real examples to test, so be safe.
   1109 	 */
   1110 	len = p->hdr.Length - sizeof(*p);
   1111 	name = emalloc(len + 1);
   1112 	memcpy(name, p->TargetName, len);
   1113 	name[len] = '\0';
   1114 
   1115 	auth = auth_name(p->LoginOptions);
   1116 	datdgst = datdgst_name(p->LoginOptions);
   1117 	hdrdgst = hdrdgst_name(p->LoginOptions);
   1118 	proto = protocol_name(p->Protocol);
   1119 
   1120 	path->sz = easprintf(&path->cp, "iSCSI(%s,0x%04x,0x%064" PRIx64
   1121 	    ",%s,%s,%s,%s)", p->TargetName, p->TargetPortalGrp,
   1122 	    htobe64(p->LUN), hdrdgst, datdgst, auth, proto);
   1123 
   1124 	if (dbg != NULL) {
   1125 		char liopt[256];
   1126 
   1127 		snprintb(liopt, sizeof(liopt), LOGIN_OPTION_BITS,
   1128 		    p->LoginOptions);
   1129 		dbg->sz = easprintf(&dbg->cp,
   1130 		    DEVPATH_FMT_HDR
   1131 		    DEVPATH_FMT(Protocol: 0x%04x(%s)\n)
   1132 		    DEVPATH_FMT(LoginOptions: %s\n)
   1133 		    DEVPATH_FMT(LUN:) " 0x%064" PRIx64 "\n"
   1134 		    DEVPATH_FMT(TargetPortalGrp: 0x%04x\n)
   1135 		    DEVPATH_FMT(TargetName: %s\n),
   1136 		    DEVPATH_DAT_HDR(dp),
   1137 		    p->Protocol, proto,
   1138 		    liopt,
   1139 		    htobe64(p->LUN),
   1140 		    p->TargetPortalGrp,
   1141 		    name);
   1142 	}
   1143 
   1144 	free(name);
   1145 }
   1146 
   1147 static void
   1148 devpath_msg_vlan(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1149 {	/* See 10.3.4.13 */
   1150 	struct {			/* Sub-Type 20 */
   1151 		devpath_t	hdr;	/* Length = 6 */
   1152 		uint16_t	Vlanid;
   1153 	} __packed *p = (void *)dp;
   1154 	__CTASSERT(sizeof(*p) == 6);
   1155 
   1156 	path->sz = easprintf(&path->cp, "Vlan(0x%04x)", p->Vlanid);
   1157 
   1158 	if (dbg != NULL) {
   1159 		dbg->sz = easprintf(&dbg->cp,
   1160 		    DEVPATH_FMT_HDR
   1161 		    DEVPATH_FMT(Vlanid: 0x%04x\n),
   1162 		    DEVPATH_DAT_HDR(dp),
   1163 		    p->Vlanid);
   1164 	}
   1165 }
   1166 
   1167 static void
   1168 devpath_msg_fibreex(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1169 {	/* See 10.3.4.3 */
   1170 	struct {			/* Sub-Type 21 */
   1171 		devpath_t	hdr;	/* Length = 24 */
   1172 		uint32_t	Reserved;
   1173 		uint64_t	WorldWideName;	/* bit-endian */
   1174 		uint64_t	LUN;		/* bit-endian */
   1175 	} __packed *p = (void *)dp;
   1176 	__CTASSERT(sizeof(*p) == 24);
   1177 
   1178 	path->sz = easprintf(&path->cp, "FibreEx(0x%064" PRIx64 ",0x%064"
   1179 	    PRIx64 ")", htobe64(p->WorldWideName), htobe64(p->LUN));
   1180 
   1181 	if (dbg != NULL) {
   1182 		dbg->sz = easprintf(&dbg->cp,
   1183 		    DEVPATH_FMT_HDR
   1184 		    DEVPATH_FMT(WorldWideName:) " 0x%064" PRIx64 "\n"
   1185 		    DEVPATH_FMT(LUN:) " 0x%064" PRIx64 "\n",
   1186 		    DEVPATH_DAT_HDR(dp),
   1187 		    htobe64(p->WorldWideName),
   1188 		    htobe64(p->LUN));
   1189 	}
   1190 }
   1191 
   1192 static void
   1193 devpath_msg_sasex(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1194 {	/* See 10.3.4.18 */
   1195 	struct {			/* Sub-Type 22 */
   1196 		devpath_t	hdr;	/* Length = 24 XXX: 32 in text */
   1197 		uint64_t	addr;	/* display as big-endian */
   1198 		uint64_t	LUN;	/* display as big-endian */
   1199 		union {
   1200 			uint8_t b[2];
   1201 			uint16_t val;
   1202 		} __packed info;	/* device/topology info */
   1203 		uint16_t	RTP;	/* Relative Target Port */
   1204 	} __packed *p = (void *)dp;
   1205 	__CTASSERT(sizeof(*p) == 24);
   1206 
   1207 	/*
   1208 	 * XXX: This should match what is in devpath_msg_sas().
   1209 	 * Should we share code?
   1210 	 */
   1211 	if (SASINFO_BYTES(p->info.b[0]) == 0) {
   1212 		path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64
   1213 		    ",0x%064" PRIx64 ")",
   1214 		    htobe64(p->addr), htobe64(p->LUN));
   1215 	}
   1216 	else if (SASINFO_BYTES(p->info.b[0]) == 1) {
   1217 		if (SASINFO_IS_SATA(p->info.b[0])) {
   1218 			path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64
   1219 			    ",0x%064" PRIx64 ",SATA)",
   1220 			    htobe64(p->addr), htobe64(p->LUN));
   1221 		}
   1222 		else {
   1223 			path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64
   1224 			    ",SAS)", htobe64(p->addr));
   1225 		}
   1226 	}
   1227 	else {
   1228 		assert(SASINFO_BYTES(p->info.b[0]) == 2);
   1229 		uint drivebay = p->info.b[1] + 1;
   1230 		path->sz = easprintf(&path->cp, "SasEx(0x%064" PRIx64
   1231 		    ",0x%064" PRIx64 ",0x%04x,%s,%s,%s,%d)",
   1232 		    htobe64(p->addr), htobe64(p->LUN), p->RTP,
   1233 		    SASINFO_SASSATA(p->info.b[0]),
   1234 		    SASINFO_EXTERNAL(p->info.b[0]),
   1235 		    SASINFO_EXPANDER(p->info.b[0]),
   1236 		    drivebay);
   1237 	}
   1238 
   1239 	if (dbg != NULL) {
   1240 		dbg->sz = easprintf(&dbg->cp,
   1241 		    DEVPATH_FMT_HDR
   1242 		    DEVPATH_FMT(addr:) " 0x%064" PRIx64 "(0x%064" PRIx64 ")\n"
   1243 		    DEVPATH_FMT(LUN:) "  0x%064" PRIx64 "(0x%064" PRIx64 ")\n"
   1244 		    DEVPATH_FMT(info: 0x%02x 0x%02x\n)
   1245 		    DEVPATH_FMT(RPT:  0x%04x\n),
   1246 		    DEVPATH_DAT_HDR(dp),
   1247 		    p->addr, htobe64(p->addr),
   1248 		    p->LUN,  htobe64(p->LUN),
   1249 		    p->info.b[0], p->info.b[1],
   1250 		    p->RTP);
   1251 	}
   1252 }
   1253 
   1254 static void
   1255 devpath_msg_nvme(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1256 {	/* See 10.3.4.21 */
   1257 	struct {			/* Sub-Type 23 */
   1258 		devpath_t	hdr;	/* Length = 16 */
   1259 		uint32_t	NSID;	/* Name Space Identifier */
   1260 		union {
   1261 			uint8_t		b[8];
   1262 			uint64_t	val;
   1263 		} EUI;	/* IEEE Extended Unique Identifier */
   1264 	} __packed *p = (void *)dp;
   1265 	__CTASSERT(sizeof(*p) == 16);
   1266 
   1267 	path->sz = easprintf(&path->cp, "NVMe(0x%x,"
   1268 	    "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X)",
   1269 	    p->NSID,
   1270 	    p->EUI.b[0], p->EUI.b[1], p->EUI.b[2], p->EUI.b[3],
   1271 	    p->EUI.b[4], p->EUI.b[5], p->EUI.b[6], p->EUI.b[7]);
   1272 
   1273 	if (dbg != NULL) {
   1274 		dbg->sz = easprintf(&dbg->cp,
   1275 		    DEVPATH_FMT_HDR
   1276 		    DEVPATH_FMT(NSID: 0x%08x\n)
   1277 		    DEVPATH_FMT(EUI:) "  0x%016" PRIx64 "\n",
   1278 		    DEVPATH_DAT_HDR(dp),
   1279 		    p->NSID, p->EUI.val);
   1280 	}
   1281 }
   1282 
   1283 static void
   1284 devpath_msg_uri(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1285 {	/* See 10.3.4.22 */
   1286 	struct {			/* Sub-Type 24 */
   1287 		devpath_t	hdr;	/* Length = 4 + n */
   1288 		uint8_t		data[];
   1289 	} __packed *p = (void *)dp;
   1290 	__CTASSERT(sizeof(*p) == 4);
   1291 	size_t len;
   1292 	char *buf;
   1293 
   1294 	len = dp->Length - 4;
   1295 
   1296 	buf = emalloc(len + 1);
   1297 	if (len > 0)
   1298 		memcpy(buf, p->data, len);
   1299 	buf[len] = '\0';
   1300 
   1301 	path->sz = easprintf(&path->cp, "Uri(%s)", buf);
   1302 
   1303 	if (dbg != NULL) {
   1304 		dbg->sz = easprintf(&dbg->cp,
   1305 		    DEVPATH_FMT_HDR
   1306 		    DEVPATH_FMT(Data: %s\n),
   1307 		    DEVPATH_DAT_HDR(dp),
   1308 		    buf);
   1309 	}
   1310 	free(buf);
   1311 }
   1312 
   1313 static void
   1314 devpath_msg_ufs(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1315 {	/* See 10.3.4.23 */
   1316 	struct {			/* Sub-Type 25 */
   1317 		devpath_t	hdr;	/* Length = 6 */
   1318 		uint8_t		PUN;	/* Target ID */
   1319 		uint8_t		LUN;	/* Logical Unit Number */
   1320 	} __packed *p = (void *)dp;
   1321 	__CTASSERT(sizeof(*p) == 6);
   1322 
   1323 	path->sz = easprintf(&path->cp, "UFS(%#x,0x%02x)", p->PUN, p->LUN);
   1324 
   1325 	if (dbg != NULL) {
   1326 		dbg->sz = easprintf(&dbg->cp,
   1327 		    DEVPATH_FMT_HDR
   1328 		    DEVPATH_FMT(PUN: 0x%02x\n)
   1329 		    DEVPATH_FMT(LUN: 0x%02x\n),
   1330 		    DEVPATH_DAT_HDR(dp),
   1331 		    p->PUN, p->LUN);
   1332 	}
   1333 }
   1334 
   1335 static void
   1336 devpath_msg_sd(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1337 {	/* See 10.3.4.24 */
   1338 	struct {			/* Sub-Type 26 */
   1339 		devpath_t	hdr;	/* Length = 5 */
   1340 		uint8_t		SlotNum;
   1341 	} __packed *p = (void *)dp;
   1342 	__CTASSERT(sizeof(*p) == 5);
   1343 
   1344 	path->sz = easprintf(&path->cp, "SD(%d)", p->SlotNum);
   1345 
   1346 	if (dbg != NULL) {
   1347 		dbg->sz = easprintf(&dbg->cp,
   1348 		    DEVPATH_FMT_HDR
   1349 		    DEVPATH_FMT(SlotNum: 0x%02x\n),
   1350 		    DEVPATH_DAT_HDR(dp),
   1351 		    p->SlotNum);
   1352 	}
   1353 }
   1354 
   1355 static void
   1356 devpath_msg_bluetooth(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1357 {	/* See 10.3.4.25 */
   1358 	struct {			/* Sub-Type 27 */
   1359 		devpath_t	hdr;	/* Length = 10 */
   1360 		uint8_t		bdaddr[6];
   1361 	} __packed *p = (void *)dp;
   1362 	__CTASSERT(sizeof(*p) == 10);
   1363 
   1364 	path->sz = easprintf(&path->cp,
   1365 	    "Bluetooth(%02x:%02x:%02x:%02x:%02x:%02x)",
   1366 	    p->bdaddr[0], p->bdaddr[1], p->bdaddr[2],
   1367 	    p->bdaddr[3], p->bdaddr[4], p->bdaddr[5]);
   1368 
   1369 	if (dbg != NULL) {
   1370 		dbg->sz = easprintf(&dbg->cp,
   1371 		    DEVPATH_FMT_HDR
   1372 		    DEVPATH_FMT(bdaddr: 0x%02x%02x%02x%02x%02x%02x\n),
   1373 		    DEVPATH_DAT_HDR(dp),
   1374 		    p->bdaddr[0], p->bdaddr[1], p->bdaddr[2],
   1375 		    p->bdaddr[3], p->bdaddr[4], p->bdaddr[5]);
   1376 	}
   1377 }
   1378 
   1379 static void
   1380 devpath_msg_wifi(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1381 {	/* See 10.3.4.26 */
   1382 	struct {			/* Sub-Type 28 */
   1383 		devpath_t	hdr;	/* Length = 36 */
   1384 		char		SSID[32];/* XXX: ascii? */
   1385 	} __packed *p = (void *)dp;
   1386 	__CTASSERT(sizeof(*p) == 36);
   1387 
   1388 	path->sz = easprintf(&path->cp, "Wi-Fi(%s)", p->SSID);
   1389 
   1390 	if (dbg != NULL) {
   1391 		char *ssid;
   1392 
   1393 		ssid = encode_data((uint8_t *)p->SSID, sizeof(p->SSID));
   1394 		dbg->sz = easprintf(&dbg->cp,
   1395 		    DEVPATH_FMT_HDR
   1396 		    DEVPATH_FMT(SSID: %s\n),
   1397 		    DEVPATH_DAT_HDR(dp),
   1398 		    ssid);
   1399 		free(ssid);
   1400 	}
   1401 }
   1402 
   1403 static void
   1404 devpath_msg_emmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1405 {	/* See 10.3.4.27 */
   1406 	struct {			/* Sub-Type 29 */
   1407 		devpath_t	hdr;	/* Length = 5 */
   1408 		uint8_t		SlotNum;
   1409 	} __packed *p = (void *)dp;
   1410 	__CTASSERT(sizeof(*p) == 5);
   1411 
   1412 	path->sz = easprintf(&path->cp, "eMMC(%d)", p->SlotNum);
   1413 
   1414 	if (dbg != NULL) {
   1415 		dbg->sz = easprintf(&dbg->cp,
   1416 		    DEVPATH_FMT_HDR
   1417 		    DEVPATH_FMT(SlotNum: 0x%02x\n),
   1418 		    DEVPATH_DAT_HDR(dp),
   1419 		    p->SlotNum);
   1420 	}
   1421 }
   1422 
   1423 static void
   1424 devpath_msg_bluetoothle(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1425 {	/* See 10.3.4.28 */
   1426 	struct {			/* Sub-Type 30 */
   1427 		devpath_t	hdr;	/* Length = 11 */
   1428 		uint8_t		bdaddr[6];
   1429 		uint8_t		addr_type;
   1430 #define BDADDR_TYPE_PUBLIC	0
   1431 #define BDADDR_TYPE_RANDOM	1
   1432 	} __packed *p = (void *)dp;
   1433 	__CTASSERT(sizeof(*p) == 11);
   1434 
   1435 	path->sz = easprintf(&path->cp,
   1436 	    "BluetoothLE(%02x:%02x:%02x:%02x:%02x:%02x,%d)",
   1437 	    p->bdaddr[0], p->bdaddr[1], p->bdaddr[2],
   1438 	    p->bdaddr[3], p->bdaddr[4], p->bdaddr[5],
   1439 	    p->addr_type);
   1440 
   1441 	if (dbg != NULL) {
   1442 		dbg->sz = easprintf(&dbg->cp,
   1443 		    DEVPATH_FMT_HDR
   1444 		    DEVPATH_FMT(bdaddr: 0x%02x%02x%02x%02x%02x%02x\n)
   1445 		    DEVPATH_FMT(addr_type: 0x%02x\n),
   1446 		    DEVPATH_DAT_HDR(dp),
   1447 		    p->bdaddr[0], p->bdaddr[1], p->bdaddr[2],
   1448 		    p->bdaddr[3], p->bdaddr[4], p->bdaddr[5],
   1449 		    p->addr_type);
   1450 	}
   1451 }
   1452 
   1453 static void
   1454 devpath_msg_dns(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1455 {	/* See 10.3.4.29 */
   1456 	struct {			/* Sub-Type 31 */
   1457 		devpath_t	hdr;	/* Length = 5 + n */
   1458 		uint8_t		IsIPv6;
   1459 		uint8_t		addr[];
   1460 	} __packed *p = (void *)dp;
   1461 	__CTASSERT(sizeof(*p) == 5);
   1462 	size_t cnt, n, sz;
   1463 
   1464 	/* XXX: This is ugly at best */
   1465 
   1466 	n = p->hdr.Length - sizeof(*p);
   1467 	sz = p->IsIPv6 ? sizeof(struct in6_addr) : sizeof(uint32_t);
   1468 	cnt = n / sz;
   1469 	assert(n == cnt * sz);
   1470 	assert(cnt > 0);
   1471 
   1472 	if (cnt > 0) { /* XXX: should always be true */
   1473 		char *bp;
   1474 
   1475 #define DNS_PREFIX	"Dns("
   1476 		if (p->IsIPv6) {
   1477 			struct in6_addr *ip6addr = (void *)p->addr;
   1478 
   1479 			bp = path->cp = malloc(sizeof(DNS_PREFIX) +
   1480 			    cnt * INET6_ADDRSTRLEN);
   1481 			bp = stpcpy(bp, DNS_PREFIX);
   1482 			bp = stpcpy(bp, ipv6_addr(&ip6addr[0]));
   1483 			for (size_t i = 1; i < cnt; i++) {
   1484 				*bp++ = ',';
   1485 				bp = stpcpy(bp, ipv6_addr(&ip6addr[i]));
   1486 			}
   1487 			*bp = ')';
   1488 		}
   1489 		else {	/* IPv4 */
   1490 			uint32_t *ip4addr = (void *)p->addr;
   1491 
   1492 			bp = path->cp = malloc(sizeof(DNS_PREFIX) +
   1493 			    cnt * INET_ADDRSTRLEN);
   1494 			bp = stpcpy(bp, DNS_PREFIX);
   1495 			bp = stpcpy(bp, ipv4_addr(ip4addr[0]));
   1496 			for (size_t i = 1; i < cnt; i++) {
   1497 				*bp++ = ',';
   1498 				bp = stpcpy(bp, ipv4_addr(ip4addr[i]));
   1499 			}
   1500 			*bp = ')';
   1501 		}
   1502 #undef DNS_PREFIX
   1503 		path->sz = strlen(bp);
   1504 	}
   1505 
   1506 	if (dbg != NULL) {
   1507 		dbg->sz = easprintf(&dbg->cp,
   1508 		    DEVPATH_FMT_HDR
   1509 		    DEVPATH_FMT(IsIPv6: %d\n),
   1510 		    DEVPATH_DAT_HDR(dp),
   1511 		    p->IsIPv6);
   1512 
   1513 		if (cnt > 0) { /* XXX: should always be true */
   1514 			char *bp, *tp;
   1515 
   1516 			bp = dbg->cp;
   1517 			if (p->IsIPv6) {
   1518 				struct in6_addr *ip6addr = (void *)p->addr;
   1519 
   1520 				for (size_t i = 0; i < cnt; i++) {
   1521 					uint8_t *cp;
   1522 
   1523 					cp = ip6addr[i].__u6_addr.__u6_addr8;
   1524 					tp = bp;
   1525 					dbg->sz += easprintf(&bp,
   1526 					    "%s"
   1527 					    DEVPATH_FMT(addr[%zu]:)
   1528 					    " %02x %02x %02x %02x"
   1529 					    " %02x %02x %02x %02x"
   1530 					    " %02x %02x %02x %02x"
   1531 					    " %02x %02x %02x %02x\n",
   1532 					    tp,
   1533 					    i,
   1534 					    cp[0],  cp[1],  cp[2],  cp[3],
   1535 					    cp[4],  cp[5],  cp[6],  cp[7],
   1536 					    cp[8],  cp[9],  cp[10], cp[11],
   1537 					    cp[12], cp[13], cp[14], cp[15]);
   1538 					free(tp);
   1539 				}
   1540 			}
   1541 			else {	/* IPv4 */
   1542 				uint32_t *ip4addr = (void *)p->addr;
   1543 
   1544 				for (size_t i = 0; i < cnt; i++) {
   1545 					tp = bp;
   1546 					dbg->sz += easprintf(&bp,
   1547 					    "%s"
   1548 					    DEVPATH_FMT(addr[i]: 0x%08x\n),
   1549 					    tp, ip4addr[i]);
   1550 					free(tp);
   1551 				}
   1552 			}
   1553 		}
   1554 	}
   1555 }
   1556 
   1557 static void
   1558 devpath_msg_nvdimm(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1559 {	/* See 10.3.4.30 */
   1560 	struct {			/* Sub-Type 32 */
   1561 		devpath_t	hdr;	/* Length = 20 */
   1562 		uuid_t		UUID;
   1563 	} __packed *p = (void *)dp;
   1564 	__CTASSERT(sizeof(*p) == 20);
   1565 	char uuid_str[UUID_STR_LEN];
   1566 
   1567 	uuid_snprintf(uuid_str, sizeof(uuid_str), &p->UUID);
   1568 	path->sz = easprintf(&path->cp, "NVDIMM(%s)", uuid_str);
   1569 
   1570 	if (dbg != NULL) {
   1571 		dbg->sz = easprintf(&dbg->cp,
   1572 		    DEVPATH_FMT_HDR,
   1573 		    DEVPATH_DAT_HDR(dp)
   1574 		);
   1575 	}
   1576 }
   1577 
   1578 static void
   1579 devpath_msg_restservice(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1580 {	/* See 10.3.4.31 */
   1581 	struct {			/* Sub-Type 33 */
   1582 		devpath_t	hdr;	/* Length = 6 */
   1583 		uint8_t		RestService;
   1584 #define REST_SERVICE_REDFISH	0x01
   1585 #define REST_SERVICE_ODATA	0x02
   1586 		uint8_t		AccessMode;
   1587 #define ACCESS_MODE_IN_BAND	0x01
   1588 #define ACCESS_MODE_OUT_OF_BAND	0x02
   1589 	} __packed *p = (void *)dp;
   1590 	__CTASSERT(sizeof(*p) == 6);
   1591 
   1592 	path->sz = easprintf(&path->cp, "RestService(%d,%d)",
   1593 	    p->RestService, p->AccessMode);
   1594 
   1595 	if (dbg != NULL) {
   1596 		dbg->sz = easprintf(&dbg->cp,
   1597 		    DEVPATH_FMT_HDR
   1598 		    DEVPATH_FMT(RestService: 0x%02x(%s)\n)
   1599 		    DEVPATH_FMT(AccessMode:  0x%02x(%s)\n),
   1600 		    DEVPATH_DAT_HDR(dp),
   1601 		    p->RestService,
   1602 		    p->RestService == REST_SERVICE_REDFISH ? "RedFish" :
   1603 		    p->RestService == REST_SERVICE_ODATA ? "OData" : "???",
   1604 		    p->AccessMode,
   1605 		    p->AccessMode == ACCESS_MODE_IN_BAND ? "In-Band" :
   1606 		    p->AccessMode == ACCESS_MODE_OUT_OF_BAND ? "Out-of-Band"
   1607 			: "???");
   1608 	}
   1609 }
   1610 
   1611 static void
   1612 devpath_msg_nvmeof(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1613 {	/* See 10.3.4.32 */
   1614 	struct {			/* Sub-Type 34 */
   1615 		devpath_t	hdr;	/* Length = 21 XXX: 20 in text */
   1616 		uint8_t		NIDT;
   1617 		union {
   1618 			uint64_t	dw[2];
   1619 			uint8_t		csi;
   1620 			uint64_t	ieuid;
   1621 			uuid_t		uuid;
   1622 		} NID;	/* big-endian */
   1623 		uint8_t		SubsystemNQN[];  /* UTF-8 null-terminated */
   1624 	} __packed *p = (void *)dp;
   1625 	__CTASSERT(sizeof(*p) == 21);
   1626 	char uuid_str[UUID_STR_LEN];
   1627 
   1628 	/*
   1629 	 * See 5.1.13.2.3 of NVM-Express Base Specification Rev 2.1,
   1630 	 * in particular, Fig 315 on page 332.
   1631 	 */
   1632 	switch (p->NIDT) {
   1633 	case 0:
   1634 		path->sz = easprintf(&path->cp, "NVMEoF(%s)", p->SubsystemNQN);
   1635 		break;
   1636 	case 1:
   1637 		path->sz = easprintf(&path->cp, "NVMEoF(%s,0x%016" PRIx64
   1638 		    ")", p->SubsystemNQN, p->NID.ieuid);
   1639 		break;
   1640 	case 2:
   1641 	case 3:
   1642 		uuid_snprintf(uuid_str, sizeof(uuid_str), &p->NID.uuid);
   1643 		path->sz = easprintf(&path->cp, "NVMEoF(%s,%s)",
   1644 		    p->SubsystemNQN, uuid_str);
   1645 		break;
   1646 	case 4:
   1647 		path->sz = easprintf(&path->cp, "NVMEoF(%s,0x%02x)",
   1648 		    p->SubsystemNQN, p->NID.csi);
   1649 		break;
   1650 	default:
   1651 		path->sz = easprintf(&path->cp, "NVMEoF(%s,unknown)",
   1652 		    p->SubsystemNQN);
   1653 		break;
   1654 	}
   1655 
   1656 	if (dbg != NULL) {
   1657 		dbg->sz = easprintf(&dbg->cp,
   1658 		    DEVPATH_FMT_HDR
   1659 		    DEVPATH_FMT(NIDT: 0x%02x\n)
   1660 		    DEVPATH_FMT(NID:) " 0x%016" PRIx64 "%016" PRIx64 "\n"
   1661 		    DEVPATH_FMT(SubsystemNQN: '%s'\n),
   1662 		    DEVPATH_DAT_HDR(dp),
   1663 		    p->NIDT,
   1664 		    p->NID.dw[0], p->NID.dw[1],
   1665 		    p->SubsystemNQN);
   1666 	}
   1667 }
   1668 
   1669 PUBLIC void
   1670 devpath_msg(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
   1671 {
   1672 
   1673 	assert(dp->Type = 3);
   1674 
   1675 	switch (dp->SubType) {
   1676 	case 1:     devpath_msg_atapi(dp, path, dbg);		return;
   1677 	case 2:     devpath_msg_scsi(dp, path, dbg);		return;
   1678 	case 3:     devpath_msg_fibre(dp, path, dbg);		return;
   1679 	case 4:     devpath_msg_11394(dp, path, dbg);		return;
   1680 	case 5:     devpath_msg_usb(dp, path, dbg);		return;
   1681 	case 6:     devpath_msg_i2o(dp, path, dbg);		return;
   1682 	case 9:     devpath_msg_infiniband(dp, path, dbg);	return;
   1683 	case 10:    devpath_msg_vendor(dp, path, dbg);		return;
   1684 	case 11:    devpath_msg_mac(dp, path, dbg);		return;
   1685 	case 12:    devpath_msg_ipv4(dp, path, dbg);		return;
   1686 	case 13:    devpath_msg_ipv6(dp, path, dbg);		return;
   1687 	case 14:    devpath_msg_uart(dp, path, dbg);		return;
   1688 	case 15:    devpath_msg_usbclass(dp, path, dbg);	return;
   1689 	case 16:    devpath_msg_usbwwid(dp, path, dbg);		return;
   1690 	case 17:    devpath_msg_unit(dp, path, dbg);		return;
   1691 	case 18:    devpath_msg_sata(dp, path, dbg);		return;
   1692 	case 19:    devpath_msg_iscsi(dp, path, dbg);		return;
   1693 	case 20:    devpath_msg_vlan(dp, path, dbg);		return;
   1694 	case 21:    devpath_msg_fibreex(dp, path, dbg);		return;
   1695 	case 22:    devpath_msg_sasex(dp, path, dbg);		return;
   1696 	case 23:    devpath_msg_nvme(dp, path, dbg);		return;
   1697 	case 24:    devpath_msg_uri(dp, path, dbg);		return;
   1698 	case 25:    devpath_msg_ufs(dp, path, dbg);		return;
   1699 	case 26:    devpath_msg_sd(dp, path, dbg);		return;
   1700 	case 27:    devpath_msg_bluetooth(dp, path, dbg);	return;
   1701 	case 28:    devpath_msg_wifi(dp, path, dbg);		return;
   1702 	case 29:    devpath_msg_emmc(dp, path, dbg);		return;
   1703 	case 30:    devpath_msg_bluetoothle(dp, path, dbg);	return;
   1704 	case 31:    devpath_msg_dns(dp, path, dbg);		return;
   1705 	case 32:    devpath_msg_nvdimm(dp, path, dbg);		return;
   1706 	case 33:    devpath_msg_restservice(dp, path, dbg);	return;
   1707 	case 34:    devpath_msg_nvmeof(dp, path, dbg);		return;
   1708 	default:    devpath_unsupported(dp, path, dbg);		return;
   1709 	}
   1710 }
   1711