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