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