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