OSDN Git Service

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