OSDN Git Service

Update abixml for newer libabigail
[android-x86/external-efivar.git] / src / dp-message.c
1 /*
2  * libefivar - library for the manipulation of EFI variables
3  * Copyright 2012-2015 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2.1 of the
8  * License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "fix_coverity.h"
22
23 #include <arpa/inet.h>
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <stddef.h>
27
28 #include "efivar.h"
29
30 static ssize_t
31 format_ipv4_addr_helper(char *buf, size_t size, const char *dp_type,
32                         const uint8_t *ipaddr, int32_t port)
33 {
34         ssize_t off = 0;
35         format(buf, size, off, dp_type, "%hhu.%hhu.%hhu.%hhu",
36                ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
37         if (port > 0)
38                 format(buf, size, off, dp_type, ":%hu", (uint16_t)port);
39         return off;
40 }
41
42 static ssize_t
43 format_ipv6_addr_helper(char *buf, size_t size, const char *dp_type,
44                         const uint8_t *ipaddr, int32_t port)
45 {
46         uint16_t *ip = (uint16_t *)ipaddr;
47         ssize_t off = 0;
48
49         format(buf, size, off, dp_type, "[");
50
51         // deciding how to print an ipv6 ip requires 2 passes, because
52         // RFC5952 says we have to use :: a) only once and b) to maximum effect.
53         int largest_zero_block_size = 0;
54         int largest_zero_block_offset = -1;
55
56         int this_zero_block_size = 0;
57         int this_zero_block_offset = -1;
58
59         int in_zero_block = 0;
60
61         int i;
62         for (i = 0; i < 8; i++) {
63                 if (ip[i] != 0 && in_zero_block) {
64                         if (this_zero_block_size > largest_zero_block_size) {
65                                 largest_zero_block_size = this_zero_block_size;
66                                 largest_zero_block_offset =
67                                                         this_zero_block_offset;
68                                 this_zero_block_size = 0;
69                                 this_zero_block_offset = -1;
70                                 in_zero_block = 0;
71                         }
72                 }
73                 if (ip[i] == 0) {
74                         if (in_zero_block == 0) {
75                                 in_zero_block = 1;
76                                 this_zero_block_offset = i;
77                         }
78                         this_zero_block_size++;
79                 }
80         }
81         if (this_zero_block_size > largest_zero_block_size) {
82                 largest_zero_block_size = this_zero_block_size;
83                 largest_zero_block_offset = this_zero_block_offset;
84                 /*
85                  * clang-analyzer hates these because they're the last use,
86                  * and they don't believe in writing code so that bugs won't
87                  * be introduced later...
88                  */
89 #if 0
90                 this_zero_block_size = 0;
91                 this_zero_block_offset = -1;
92                 in_zero_block = 0;
93 #endif
94         }
95         if (largest_zero_block_size == 1)
96                 largest_zero_block_offset = -1;
97
98         for (i = 0; i < 8; i++) {
99                 if (largest_zero_block_offset == i) {
100                         format(buf, size, off, "dp_type", "::");
101                         i += largest_zero_block_size -1;
102                         continue;
103                 } else if (i > 0) {
104                         format(buf, size, off, "dp_type", ":");
105                 }
106
107                 format(buf, size, off, "dp_type", "%x", ip[i]);
108         }
109
110         format(buf, size, off, "dp_type", "]");
111         if (port >= 0)
112                 format(buf, size, off, "Ipv6", ":%hu", (uint16_t)port);
113
114         return off;
115 }
116
117 #define format_ipv4_addr(buf, size, off, addr, port)            \
118         format_helper(format_ipv4_addr_helper, buf, size, off,  \
119                       "IPv4", addr, port)
120
121 #define format_ipv6_addr(buf, size, off, addr, port)            \
122         format_helper(format_ipv6_addr_helper, buf, size, off,  \
123                       "IPv6", addr, port)
124
125 static ssize_t
126 format_ip_addr_helper(char *buf, size_t size,
127                       const char *dp_type UNUSED,
128                       int is_ipv6, const efi_ip_addr_t *addr)
129 {
130         ssize_t off = 0;
131         if (is_ipv6)
132                 format_helper(format_ipv6_addr_helper, buf, size, off, "IPv6",
133                               (const uint8_t *)&addr->v6, -1);
134         else
135                 format_helper(format_ipv4_addr_helper, buf, size, off, "IPv4",
136                               (const uint8_t *)&addr->v4, -1);
137         return off;
138 }
139
140 #define format_ip_addr(buf, size, off, dp_type, is_ipv6, addr)          \
141         format_helper(format_ip_addr_helper, buf, size, off,            \
142                       dp_type, is_ipv6, addr)
143
144 static ssize_t
145 format_uart(char *buf, size_t size,
146             const char *dp_type UNUSED,
147             const_efidp dp)
148 {
149         uint32_t value;
150         ssize_t off = 0;
151         char *labels[] = {"None", "Hardware", "XonXoff", ""};
152
153         value = dp->uart_flow_control.flow_control_map;
154         if (value > 2) {
155                 format(buf, size, off, "UartFlowControl",
156                             "UartFlowControl(%d)", value);
157                 return off;
158         }
159         format(buf, size, off, "UartFlowControl", "UartFlowControl(%s)",
160                labels[value]);
161         return off;
162 }
163
164 static ssize_t
165 format_sas(char *buf, size_t size,
166            const char *dp_type UNUSED,
167            const_efidp dp)
168 {
169         ssize_t off = 0;
170         const efidp_sas * const s = &dp->sas;
171
172         int more_info = 0;
173         int sassata = 0;
174         int location = 0;
175         int connect = 0;
176         int drive_bay = -1;
177
178         const char * const sassata_label[] = {"NoTopology", "SAS", "SATA"};
179         const char * const location_label[] = {"Internal", "External" };
180         const char * const connect_label[] = {"Direct", "Expanded" };
181
182         more_info = s->device_topology_info & EFIDP_SAS_TOPOLOGY_MASK;
183
184         if (more_info) {
185                 sassata = (s->device_topology_info & EFIDP_SAS_DEVICE_MASK)
186                           >> EFIDP_SAS_DEVICE_SHIFT;
187                 if (sassata == EFIDP_SAS_DEVICE_SATA_EXTERNAL
188                                 || sassata == EFIDP_SAS_DEVICE_SAS_EXTERNAL)
189                         location = 1;
190
191                 if (sassata == EFIDP_SAS_DEVICE_SAS_INTERNAL
192                                 || sassata == EFIDP_SAS_DEVICE_SATA_INTERNAL)
193                         sassata = 1;
194                 else
195                         sassata = 2;
196
197                 connect = (s->device_topology_info & EFIDP_SAS_CONNECT_MASK)
198                            >> EFIDP_SAS_CONNECT_SHIFT;
199                 if (more_info == EFIDP_SAS_TOPOLOGY_NEXTBYTE)
200                         drive_bay = s->drive_bay_id + 1;
201         }
202
203         format(buf, size, off, "SAS", "SAS(%"PRIx64",%"PRIx64",%"PRIx16",%s",
204                dp->subtype == EFIDP_MSG_SAS_EX ?
205                         be64_to_cpu(s->sas_address) :
206                         le64_to_cpu(s->sas_address),
207                 dp->subtype == EFIDP_MSG_SAS_EX ?
208                         be64_to_cpu(s->lun) :
209                         le64_to_cpu(s->lun),
210                 s->rtp, sassata_label[sassata]);
211
212         if (more_info) {
213                 format(buf, size, off, "SAS", ",%s,%s",
214                        location_label[location], connect_label[connect]);
215         }
216
217         if (more_info == 2 && drive_bay >= 0) {
218                 format(buf, size, off, "SAS", ",%d", drive_bay);
219         }
220
221         format(buf, size, off, "SAS", ")");
222         return off;
223 }
224
225 #define class_helper(buf, size, off, label, dp)                 \
226         format(buf, size, off, label,                           \
227                "%s(0x%"PRIx16",0x%"PRIx16",%d,%d)",             \
228                label,                                           \
229                dp->usb_class.vendor_id,                         \
230                dp->usb_class.product_id,                        \
231                dp->usb_class.device_subclass,                   \
232                dp->usb_class.device_protocol)
233
234 static ssize_t
235 format_usb_class(char *buf, size_t size,
236                  const char *dp_type UNUSED,
237                  const_efidp dp)
238 {
239         ssize_t off = 0;
240         switch (dp->usb_class.device_class) {
241         case EFIDP_USB_CLASS_AUDIO:
242                 class_helper(buf, size, off, "UsbAudio", dp);
243                 break;
244         case EFIDP_USB_CLASS_CDC_CONTROL:
245                 class_helper(buf, size, off, "UsbCDCControl", dp);
246                 break;
247         case EFIDP_USB_CLASS_HID:
248                 class_helper(buf, size, off, "UsbHID", dp);
249                 break;
250         case EFIDP_USB_CLASS_IMAGE:
251                 class_helper(buf, size, off, "UsbImage", dp);
252                 break;
253         case EFIDP_USB_CLASS_PRINTER:
254                 class_helper(buf, size, off, "UsbPrinter", dp);
255                 break;
256         case EFIDP_USB_CLASS_MASS_STORAGE:
257                 class_helper(buf, size, off, "UsbMassStorage", dp);
258                 break;
259         case EFIDP_USB_CLASS_HUB:
260                 class_helper(buf, size, off, "UsbHub", dp);
261                 break;
262         case EFIDP_USB_CLASS_CDC_DATA:
263                 class_helper(buf, size, off, "UsbCDCData", dp);
264                 break;
265         case EFIDP_USB_CLASS_SMARTCARD:
266                 class_helper(buf, size, off, "UsbSmartCard", dp);
267                 break;
268         case EFIDP_USB_CLASS_VIDEO:
269                 class_helper(buf, size, off, "UsbVideo", dp);
270                 break;
271         case EFIDP_USB_CLASS_DIAGNOSTIC:
272                 class_helper(buf, size, off, "UsbDiagnostic", dp);
273                 break;
274         case EFIDP_USB_CLASS_WIRELESS:
275                 class_helper(buf, size, off, "UsbWireless", dp);
276                 break;
277         case EFIDP_USB_CLASS_254:
278                 switch (dp->usb_class.device_subclass) {
279                 case EFIDP_USB_SUBCLASS_FW_UPDATE:
280                         format(buf, size, off, "UsbDeviceFirmwareUpdate",
281                           "UsbDeviceFirmwareUpdate(0x%"PRIx16",0x%"PRIx16",%d)",
282                           dp->usb_class.vendor_id,
283                           dp->usb_class.product_id,
284                           dp->usb_class.device_protocol);
285                         break;
286                 case EFIDP_USB_SUBCLASS_IRDA_BRIDGE:
287                         format(buf, size, off, "UsbIrdaBridge",
288                                "UsbIrdaBridge(0x%"PRIx16",0x%"PRIx16",%d)",
289                                dp->usb_class.vendor_id,
290                                dp->usb_class.product_id,
291                                dp->usb_class.device_protocol);
292                         break;
293                 case EFIDP_USB_SUBCLASS_TEST_AND_MEASURE:
294                         format(buf, size, off, "UsbTestAndMeasurement",
295                           "UsbTestAndMeasurement(0x%"PRIx16",0x%"PRIx16",%d)",
296                           dp->usb_class.vendor_id,
297                           dp->usb_class.product_id,
298                           dp->usb_class.device_protocol);
299                         break;
300                 }
301                 break;
302         default:
303                 format(buf, size, off, "UsbClass",
304                        "UsbClass(%"PRIx16",%"PRIx16",%d,%d)",
305                        dp->usb_class.vendor_id,
306                        dp->usb_class.product_id,
307                        dp->usb_class.device_subclass,
308                        dp->usb_class.device_protocol);
309                 break;
310         }
311         return off;
312 }
313
314 ssize_t
315 _format_message_dn(char *buf, size_t size, const_efidp dp)
316 {
317         ssize_t off = 0;
318         switch (dp->subtype) {
319         case EFIDP_MSG_ATAPI:
320                 format(buf, size, off, "Ata", "Ata(%d,%d,%d)",
321                               dp->atapi.primary, dp->atapi.slave,
322                               dp->atapi.lun);
323                 break;
324         case EFIDP_MSG_SCSI:
325                 format(buf, size, off, "SCSI", "SCSI(%d,%d)",
326                               dp->scsi.target, dp->scsi.lun);
327                 break;
328         case EFIDP_MSG_FIBRECHANNEL:
329                 format(buf, size, off, "Fibre", "Fibre(%"PRIx64",%"PRIx64")",
330                               le64_to_cpu(dp->fc.wwn),
331                               le64_to_cpu(dp->fc.lun));
332                 break;
333         case EFIDP_MSG_FIBRECHANNELEX:
334                 format(buf, size, off, "Fibre", "Fibre(%"PRIx64",%"PRIx64")",
335                               be64_to_cpu(dp->fc.wwn),
336                               be64_to_cpu(dp->fc.lun));
337                 break;
338         case EFIDP_MSG_1394:
339                 format(buf, size, off, "I1394", "I1394(0x%"PRIx64")",
340                               dp->firewire.guid);
341                 break;
342         case EFIDP_MSG_USB:
343                 format(buf, size, off, "USB", "USB(%d,%d)",
344                               dp->usb.parent_port, dp->usb.interface);
345                 break;
346         case EFIDP_MSG_I2O:
347                 format(buf, size, off, "I2O", "I2O(%d)", dp->i2o.target);
348                 break;
349         case EFIDP_MSG_INFINIBAND:
350                 if (dp->infiniband.resource_flags &
351                                 EFIDP_INFINIBAND_RESOURCE_IOC_SERVICE) {
352                         format(buf, size, off, "Infiniband",
353         "Infiniband(%08x,%"PRIx64"%"PRIx64",%"PRIx64",%"PRIu64",%"PRIu64")",
354                                     dp->infiniband.resource_flags,
355                                     dp->infiniband.port_gid[1],
356                                     dp->infiniband.port_gid[0],
357                                     dp->infiniband.service_id,
358                                     dp->infiniband.target_port_id,
359                                     dp->infiniband.device_id);
360                 } else {
361                         format(buf, size, off, "Infiniband",
362                                "Infiniband(%08x,%"PRIx64"%"PRIx64",",
363                                dp->infiniband.resource_flags,
364                                dp->infiniband.port_gid[1],
365                                dp->infiniband.port_gid[0]);
366                         format_guid(buf, size, off, "Infiniband",
367                                     (efi_guid_t *)&dp->infiniband.ioc_guid);
368                         format(buf, size, off, "Infiniband",
369                                ",%"PRIu64",%"PRIu64")",
370                                dp->infiniband.target_port_id,
371                                dp->infiniband.device_id);
372                 }
373                 break;
374         case EFIDP_MSG_MAC_ADDR:
375                 format(buf, size, off, "MAC", "MAC(");
376                 format_hex(buf, size, off, "MAC", dp->mac_addr.mac_addr,
377                                   dp->mac_addr.if_type < 2 ? 6
378                                         : sizeof(dp->mac_addr.mac_addr));
379                 format(buf, size, off, "MAC", ",%d)", dp->mac_addr.if_type);
380                 break;
381         case EFIDP_MSG_IPv4: {
382                 efidp_ipv4_addr const *a = &dp->ipv4_addr;
383                 format(buf, size, off, "IPv4", "IPv4(");
384                 format_ipv4_addr(buf, size, off,
385                                  a->local_ipv4_addr, a->local_port);
386                 format_ipv4_addr(buf, size, off,
387                                  a->remote_ipv4_addr, a->remote_port);
388                 format(buf, size, off, "IPv4", ",%hx,%hhx)",
389                        a->protocol, a->static_ip_addr);
390                 break;
391                              }
392         case EFIDP_MSG_VENDOR: {
393                 struct {
394                         efi_guid_t guid;
395                         char label[40];
396                         ssize_t (*formatter)(char *buf, size_t size,
397                                 const char *dp_type UNUSED,
398                                 const_efidp dp);
399                 } subtypes[] = {
400                         { .guid = EFIDP_PC_ANSI_GUID,
401                           .label = "VenPcAnsi" },
402                         { .guid = EFIDP_VT_100_GUID,
403                           .label = "VenVt100" },
404                         { .guid = EFIDP_VT_100_PLUS_GUID,
405                           .label = "VenVt100Plus" },
406                         { .guid = EFIDP_VT_UTF8_GUID,
407                           .label = "VenUtf8" },
408                         { .guid = EFIDP_MSG_DEBUGPORT_GUID,
409                           .label = "DebugPort" },
410                         { .guid = EFIDP_MSG_UART_GUID,
411                           .label = "",
412                           .formatter = format_uart },
413                         { .guid = EFIDP_MSG_SAS_GUID,
414                           .label = "",
415                           .formatter = format_sas },
416                         { .guid = efi_guid_empty,
417                           .label = "" }
418                 };
419                 char *label = NULL;
420                 ssize_t (*formatter)(char *buf, size_t size,
421                         const char *dp_type UNUSED,
422                         const_efidp dp) = NULL;
423
424                 for (int i = 0; !efi_guid_is_zero(&subtypes[i].guid); i++) {
425                         if (efi_guid_cmp(&subtypes[i].guid,
426                                           &dp->msg_vendor.vendor_guid))
427                                 continue;
428
429                         if (subtypes[i].label[0])
430                                 label = subtypes[i].label;
431                         formatter = subtypes[i].formatter;
432                         break;
433                 }
434
435                 if (!label && !formatter) {
436                         format_vendor(buf, size, off, "VenMsg", dp);
437                         break;
438                 } else if (!label && formatter) {
439                         format_helper(formatter, buf, size, off, "VenMsg", dp);
440                         break;
441                 }
442
443                 format(buf, size, off, label, "%s(", label);
444                 if (efidp_node_size(dp) >
445                                 (ssize_t)(sizeof (efidp_header)
446                                           + sizeof (efi_guid_t))) {
447                         format_hex(buf, size, off, label,
448                                           dp->msg_vendor.vendor_data,
449                                           efidp_node_size(dp)
450                                                 - sizeof (efidp_header)
451                                                 - sizeof (efi_guid_t));
452                 }
453                 format(buf, size, off, label, ")");
454                 break;
455                                }
456         case EFIDP_MSG_IPv6: {
457                 efidp_ipv6_addr const *a = &dp->ipv6_addr;
458                 char *addr0 = NULL;
459                 char *addr1 = NULL;
460                 ssize_t tmpoff = 0;
461                 ssize_t sz;
462
463                 sz = format_ipv6_addr(addr0, 0, tmpoff, a->local_ipv6_addr,
464                                       a->local_port);
465                 if (sz < 0)
466                         return -1;
467                 addr0 = alloca(sz+1);
468                 tmpoff = 0;
469                 sz = format_ipv6_addr(addr1, 0, tmpoff, a->remote_ipv6_addr,
470                                       a->remote_port);
471                 if (sz < 0)
472                         return -1;
473                 addr1 = alloca(sz+1);
474
475                 tmpoff = 0;
476                 format_ipv6_addr(addr0, sz, tmpoff, a->local_ipv6_addr,
477                                  a->local_port);
478
479                 tmpoff = 0;
480                 format_ipv6_addr(addr1, sz, tmpoff, a->remote_ipv6_addr,
481                                  a->remote_port);
482
483                 format(buf, size, off, "IPv6", "IPv6(%s<->%s,%hx,%hhx)",
484                        addr0, addr1, a->protocol, a->ip_addr_origin);
485                 break;
486                              }
487         case EFIDP_MSG_UART: {
488                 int parity = dp->uart.parity;
489                 char parity_label[] = "DNEOMS";
490                 int stop_bits = dp->uart.stop_bits;
491                 char *sb_label[] = {"D", "1", "1.5", "2"};
492
493                 format(buf, size, off, "Uart", "Uart(%"PRIu64",%d,",
494                             dp->uart.baud_rate ? dp->uart.baud_rate : 115200,
495                             dp->uart.data_bits ? dp->uart.data_bits : 8);
496                 format(buf, size, off, "Uart",
497                             parity > 5 ? "%d," : "%c,",
498                             parity > 5 ? parity : parity_label[parity]);
499                 if (stop_bits > 3)
500                         format(buf, size, off, "Uart", "%d)", stop_bits);
501                 else
502                         format(buf, size, off, "Uart", "%s)",
503                                sb_label[stop_bits]);
504                 break;
505                              }
506         case EFIDP_MSG_USB_CLASS:
507                 format_helper(format_usb_class, buf, size, off, "UsbClass", dp);
508                 break;
509         case EFIDP_MSG_USB_WWID: {
510                 size_t limit = (efidp_node_size(dp)
511                                 - offsetof(efidp_usb_wwid, serial_number))
512                                 / 2;
513                 format(buf, size, off, "UsbWwid",
514                             "UsbWwid(%"PRIx16",%"PRIx16",%d,",
515                             dp->usb_wwid.vendor_id, dp->usb_wwid.product_id,
516                             dp->usb_wwid.interface);
517                 format_ucs2(buf, size, off, "UsbWwid",
518                             dp->usb_wwid.serial_number, limit);
519                 format(buf, size, off, "UsbWwid", ")");
520                 break;
521                                  }
522         case EFIDP_MSG_LUN:
523                 format(buf, size, off, "Unit", "Unit(%d)", dp->lun.lun);
524                 break;
525         case EFIDP_MSG_SATA:
526                 format(buf, size, off, "Sata", "Sata(%d,%d,%d)",
527                             dp->sata.hba_port, dp->sata.port_multiplier_port,
528                             dp->sata.lun);
529                 break;
530         case EFIDP_MSG_ISCSI: {
531                 ssize_t sz = efidp_node_size(dp)
532                         - offsetof(efidp_iscsi, target_name);
533                 if (sz < 0) {
534                         efi_error("bad DP node size");
535                         return -1;
536                 }
537
538                 if (sz > EFIDP_ISCSI_MAX_TARGET_NAME_LEN)
539                         sz = EFIDP_ISCSI_MAX_TARGET_NAME_LEN;
540
541                 char target_name[sz + 1];
542                 memcpy(target_name, dp->iscsi.target_name, sz);
543                 target_name[sz] = '\0';
544                 uint64_t lun;
545
546                 memcpy(&lun, dp->iscsi.lun, sizeof (lun));
547
548                 format(buf, size, off, "iSCSI",
549                               "iSCSI(%s,%d,0x%"PRIx64",%s,%s,%s,%s)",
550                               target_name, dp->iscsi.tpgt,
551                               be64_to_cpu(lun),
552                               (dp->iscsi.options >> EFIDP_ISCSI_HEADER_DIGEST_SHIFT) & EFIDP_ISCSI_HEADER_CRC32 ? "CRC32" : "None",
553                               (dp->iscsi.options >> EFIDP_ISCSI_DATA_DIGEST_SHIFT) & EFIDP_ISCSI_DATA_CRC32 ? "CRC32" : "None",
554                               (dp->iscsi.options >> EFIDP_ISCSI_AUTH_SHIFT) & EFIDP_ISCSI_AUTH_NONE ? "None" : \
555                                       (dp->iscsi.options >> EFIDP_ISCSI_CHAP_SHIFT) & EFIDP_ISCSI_CHAP_UNI ? "CHAP_UNI" : "CHAP_BI",
556                               dp->iscsi.protocol == 0 ? "TCP" : "Unknown");
557                 break;
558                               }
559         case EFIDP_MSG_VLAN:
560                 format(buf, size, off, "Vlan", "Vlan(%d)", dp->vlan.vlan_id);
561                 break;
562         case EFIDP_MSG_SAS_EX:
563                 format_sas(buf, size, NULL, dp);
564                 break;
565         case EFIDP_MSG_NVME:
566                 format(buf, size, off, "NVMe", "NVMe(0x%"PRIx32","
567                            "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X)",
568                            dp->nvme.namespace_id, dp->nvme.ieee_eui_64[0],
569                            dp->nvme.ieee_eui_64[1], dp->nvme.ieee_eui_64[2],
570                            dp->nvme.ieee_eui_64[3], dp->nvme.ieee_eui_64[4],
571                            dp->nvme.ieee_eui_64[5], dp->nvme.ieee_eui_64[6],
572                            dp->nvme.ieee_eui_64[7]);
573                 break;
574         case EFIDP_MSG_URI: {
575                 ssize_t sz = efidp_node_size(dp) - offsetof(efidp_uri, uri);
576                 if (sz < 0) {
577                         efi_error("bad DP node size");
578                         return -1;
579                 }
580
581                 char uri[sz + 1];
582                 memcpy(uri, dp->uri.uri, sz);
583                 uri[sz] = '\0';
584                 format(buf, size, off, "Uri", "Uri(%s)", uri);
585                 break;
586                             }
587         case EFIDP_MSG_UFS:
588                 format(buf, size, off, "UFS", "UFS(%d,0x%02x)",
589                             dp->ufs.target_id, dp->ufs.lun);
590                 break;
591         case EFIDP_MSG_SD:
592                 format(buf, size, off, "SD", "SD(%d)", dp->sd.slot_number);
593                 break;
594         case EFIDP_MSG_BT:
595                 format(buf, size, off, "Bluetooth", "Bluetooth(");
596                 format_hex_separated(buf, size, off, "Bluetooth", ":", 1,
597                                      dp->bt.addr, sizeof(dp->bt.addr));
598                 format(buf, size, off, "Bluetooth", ")");
599                 break;
600         case EFIDP_MSG_WIFI:
601                 format(buf, size, off, "Wi-Fi", "Wi-Fi(");
602                 format_hex_separated(buf, size, off, "Wi-Fi", ":", 1,
603                                      dp->wifi.ssid, sizeof(dp->wifi.ssid));
604                 format(buf, size, off, "Wi-Fi", ")");
605                 break;
606         case EFIDP_MSG_EMMC:
607                 format(buf, size, off, "eMMC", "eMMC(%d)", dp->emmc.slot);
608                 break;
609         case EFIDP_MSG_BTLE:
610                 format(buf, size, off, "BluetoothLE", "BluetoothLE(");
611                 format_hex_separated(buf, size, off, "BluetoothLE", ":", 1,
612                                      dp->btle.addr, sizeof(dp->btle.addr));
613                 format(buf, size, off, "BluetoothLE", ",%d)",
614                        dp->btle.addr_type);
615                 break;
616         case EFIDP_MSG_DNS: {
617                 int end = (efidp_node_size(dp)
618                            - sizeof(dp->dns.header)
619                            - sizeof(dp->dns.is_ipv6)
620                           ) / sizeof(efi_ip_addr_t);
621                 format(buf, size, off, "Dns", "Dns(");
622                 for (int i=0; i < end; i++) {
623                         const efi_ip_addr_t *addr = &dp->dns.addrs[i];
624                         if (i != 0)
625                                 format(buf, size, off, "Dns", ",");
626                         format_ip_addr(buf, size, off, "Dns",
627                                        dp->dns.is_ipv6, addr);
628                 }
629                 format(buf, size, off, "Dns", ")");
630                 break;
631         }
632         case EFIDP_MSG_NVDIMM:
633                 format(buf, size, off, "NVDIMM", "NVDIMM(");
634                 format_guid(buf, size, off, "NVDIMM", &dp->nvdimm.uuid);
635                 format(buf, size, off, "NVDIMM", ")");
636                 break;
637         default:
638                 format(buf, size, off, "Msg", "Msg(%d,", dp->subtype);
639                 format_hex(buf, size, off, "Msg", (uint8_t *)dp+4,
640                                 efidp_node_size(dp)-4);
641                 format(buf, size, off, "Msg", ")");
642                 break;
643         }
644         return off;
645 }
646
647 ssize_t PUBLIC
648 efidp_make_mac_addr(uint8_t *buf, ssize_t size, uint8_t if_type,
649                     const uint8_t * const mac_addr, ssize_t mac_addr_size)
650 {
651         efidp_mac_addr *mac = (efidp_mac_addr *)buf;
652
653         ssize_t sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
654                                         EFIDP_MSG_MAC_ADDR, sizeof (*mac));
655         ssize_t req = sizeof (*mac);
656         if (size && sz == req) {
657                 mac->if_type = if_type;
658                 memcpy(mac->mac_addr, mac_addr,
659                        mac_addr_size > 32 ? 32 : mac_addr_size);
660         }
661
662         if (sz < 0)
663                 efi_error("efidp_make_generic failed");
664
665         return sz;
666 }
667
668 ssize_t PUBLIC
669 efidp_make_ipv4(uint8_t *buf, ssize_t size, uint32_t local, uint32_t remote,
670                 uint32_t gateway, uint32_t netmask,
671                 uint16_t local_port, uint16_t remote_port,
672                 uint16_t protocol, int is_static)
673 {
674         efidp_ipv4_addr *ipv4 = (efidp_ipv4_addr *)buf;
675         ssize_t sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
676                                         EFIDP_MSG_IPv4, sizeof (*ipv4));
677         ssize_t req = sizeof (*ipv4);
678         if (size && sz == req) {
679                 *((char *)ipv4->local_ipv4_addr) = htonl(local);
680                 *((char *)ipv4->remote_ipv4_addr) = htonl(remote);
681                 ipv4->local_port = htons(local_port);
682                 ipv4->remote_port = htons(remote_port);
683                 ipv4->protocol = htons(protocol);
684                 ipv4->static_ip_addr = 0;
685                 if (is_static)
686                         ipv4->static_ip_addr = 1;
687                 *((char *)ipv4->gateway) = htonl(gateway);
688                 *((char *)ipv4->netmask) = htonl(netmask);
689         }
690
691         if (sz < 0)
692                 efi_error("efidp_make_generic failed");
693
694         return sz;
695 }
696
697 ssize_t PUBLIC
698 efidp_make_scsi(uint8_t *buf, ssize_t size, uint16_t target, uint16_t lun)
699 {
700         efidp_scsi *scsi = (efidp_scsi *)buf;
701         ssize_t req = sizeof (*scsi);
702         ssize_t sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
703                                         EFIDP_MSG_SCSI, sizeof (*scsi));
704         if (size && sz == req) {
705                 scsi->target = target;
706                 scsi->lun = lun;
707         }
708
709         if (sz < 0)
710                 efi_error("efidp_make_generic failed");
711
712         return sz;
713 }
714
715 ssize_t PUBLIC
716 efidp_make_nvme(uint8_t *buf, ssize_t size, uint32_t namespace_id,
717                 uint8_t *ieee_eui_64)
718 {
719         efidp_nvme *nvme = (efidp_nvme *)buf;
720         ssize_t req = sizeof (*nvme);
721         ssize_t sz;
722
723         sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
724                                         EFIDP_MSG_NVME, sizeof (*nvme));
725         if (size && sz == req) {
726                 nvme->namespace_id = namespace_id;
727                 if (ieee_eui_64)
728                         memcpy(nvme->ieee_eui_64, ieee_eui_64,
729                                sizeof (nvme->ieee_eui_64));
730                 else
731                         memset(nvme->ieee_eui_64, '\0',
732                                sizeof (nvme->ieee_eui_64));
733         }
734
735         if (sz < 0)
736                 efi_error("efidp_make_generic failed");
737
738         return sz;
739 }
740
741 ssize_t PUBLIC
742 efidp_make_sata(uint8_t *buf, ssize_t size, uint16_t hba_port,
743                 int16_t port_multiplier_port, uint16_t lun)
744 {
745         efidp_sata *sata = (efidp_sata *)buf;
746         ssize_t req = sizeof (*sata);
747         ssize_t sz;
748
749         sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
750                                         EFIDP_MSG_SATA, sizeof (*sata));
751         if (size && sz == req) {
752                 sata->hba_port = hba_port;
753                 sata->port_multiplier_port = port_multiplier_port;
754                 sata->lun = lun;
755         }
756
757         if (sz < 0)
758                 efi_error("efidp_make_generic failed");
759
760         return sz;
761 }
762
763 ssize_t PUBLIC
764 efidp_make_atapi(uint8_t *buf, ssize_t size, uint16_t primary,
765                 uint16_t slave, uint16_t lun)
766 {
767         efidp_atapi *atapi = (efidp_atapi *)buf;
768         ssize_t req = sizeof (*atapi);
769         ssize_t sz;
770
771         sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
772                                         EFIDP_MSG_ATAPI, sizeof (*atapi));
773         if (size && sz == req) {
774                 atapi->primary = primary;
775                 atapi->slave = slave;
776                 atapi->lun = lun;
777         }
778
779         if (sz < 0)
780                 efi_error("efidp_make_generic failed");
781
782         return sz;
783 }
784
785
786 ssize_t PUBLIC
787 efidp_make_sas(uint8_t *buf, ssize_t size, uint64_t sas_address)
788 {
789         efidp_sas *sas = (efidp_sas *)buf;
790         ssize_t req = sizeof (*sas);
791         ssize_t sz;
792
793         sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
794                                         EFIDP_MSG_VENDOR, sizeof (*sas));
795         if (size && sz == req) {
796                 sas->vendor_guid = EFIDP_MSG_SAS_GUID;
797                 sas->reserved = 0;
798                 sas->sas_address = sas_address;
799                 sas->lun = 0;
800                 sas->device_topology_info = 0;
801                 sas->drive_bay_id = 0;
802                 sas->rtp = 0;
803         }
804
805         if (sz < 0)
806                 efi_error("efidp_make_generic failed");
807
808         return sz;
809 }
810
811 ssize_t PUBLIC
812 efidp_make_nvdimm(uint8_t *buf, ssize_t size, efi_guid_t *uuid)
813 {
814         efidp_nvdimm *nvdimm = (efidp_nvdimm *)buf;
815         ssize_t req = sizeof (*nvdimm);
816         ssize_t sz;
817
818         sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
819                                 EFIDP_MSG_NVDIMM, sizeof (*nvdimm));
820         if (size && sz == req) {
821                 memcpy(&nvdimm->uuid, uuid, sizeof(*uuid));
822         }
823
824         if (sz < 0)
825                 efi_error("efidp_make_generic failed");
826
827         return sz;
828 }
829
830 ssize_t PUBLIC
831 efidp_make_emmc(uint8_t *buf, ssize_t size, uint32_t slot_id)
832 {
833         efidp_emmc *emmc = (efidp_emmc *)buf;
834         ssize_t req = sizeof (*emmc);
835         ssize_t sz;
836
837         sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE,
838                                         EFIDP_MSG_NVME, sizeof (*emmc));
839         if (size && sz == req)
840                 emmc->slot = slot_id;
841
842         if (sz < 0)
843                 efi_error("efidp_make_generic failed");
844
845         return sz;
846 }