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