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