Blame SOURCES/0200-efinet-and-bootp-add-support-for-dhcpv6.patch

d41074
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a85e8e
From: Peter Jones <pjones@redhat.com>
a85e8e
Date: Wed, 8 Jun 2016 21:03:37 -0400
d41074
Subject: [PATCH] efinet and bootp: add support for dhcpv6
a85e8e
a85e8e
Signed-off-by: Peter Jones <pjones@redhat.com>
a85e8e
---
a85e8e
 grub-core/net/bootp.c              | 173 +++++++++++++++++++++++++++++++++++++
a85e8e
 grub-core/net/drivers/efi/efinet.c |  52 +++++++++--
a85e8e
 grub-core/net/net.c                |  67 ++++++++++++++
a85e8e
 grub-core/net/tftp.c               |   4 +
a85e8e
 include/grub/efi/api.h             | 129 +++++++++++++++++++++++++--
a85e8e
 include/grub/net.h                 |  60 +++++++++++++
a85e8e
 6 files changed, 471 insertions(+), 14 deletions(-)
a85e8e
a85e8e
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
d41074
index 88f20568914..4793ebc434e 100644
a85e8e
--- a/grub-core/net/bootp.c
a85e8e
+++ b/grub-core/net/bootp.c
a85e8e
@@ -23,6 +23,7 @@
a85e8e
 #include <grub/net/ip.h>
a85e8e
 #include <grub/net/netbuff.h>
a85e8e
 #include <grub/net/udp.h>
a85e8e
+#include <grub/net/url.h>
a85e8e
 #include <grub/datetime.h>
a85e8e
 
a85e8e
 static char *
a85e8e
@@ -335,6 +336,178 @@ grub_net_configure_by_dhcp_ack (const char *name,
a85e8e
   return inter;
a85e8e
 }
a85e8e
 
a85e8e
+struct grub_net_network_level_interface *
a85e8e
+grub_net_configure_by_dhcpv6_ack (const char *name,
a85e8e
+				  struct grub_net_card *card,
a85e8e
+				  grub_net_interface_flags_t flags
a85e8e
+				    __attribute__((__unused__)),
a85e8e
+				  const grub_net_link_level_address_t *hwaddr,
a85e8e
+				  const struct grub_net_dhcpv6_packet *packet,
a85e8e
+				  int is_def, char **device, char **path)
a85e8e
+{
a85e8e
+  struct grub_net_network_level_interface *inter = NULL;
a85e8e
+  struct grub_net_network_level_address addr;
a85e8e
+  int mask = -1;
a85e8e
+
a85e8e
+  if (device)
a85e8e
+    *device = 0;
a85e8e
+  if (path)
a85e8e
+    *path = 0;
a85e8e
+
a85e8e
+  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
a85e8e
+		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
a85e8e
+		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
a85e8e
+
a85e8e
+  if (is_def)
a85e8e
+    grub_net_default_server = 0;
a85e8e
+
a85e8e
+  if (is_def && !grub_net_default_server && packet)
a85e8e
+    {
a85e8e
+      const grub_uint8_t *options = packet->dhcp_options;
a85e8e
+      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
a85e8e
+      unsigned int i;
a85e8e
+
a85e8e
+      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
a85e8e
+	{
a85e8e
+	  grub_uint16_t num, len;
a85e8e
+	  grub_net_dhcpv6_option_t *opt =
a85e8e
+	    (grub_net_dhcpv6_option_t *)(options + i);
a85e8e
+
a85e8e
+	  num = grub_be_to_cpu16(opt->option_num);
a85e8e
+	  len = grub_be_to_cpu16(opt->option_len);
a85e8e
+
a85e8e
+	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
a85e8e
+
a85e8e
+	  if (len == 0)
a85e8e
+	    break;
a85e8e
+
a85e8e
+	  if (len + i > 1024)
a85e8e
+	    break;
a85e8e
+
a85e8e
+	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
a85e8e
+	    {
a85e8e
+	      char *scheme, *userinfo, *host, *file;
a85e8e
+	      char *tmp;
a85e8e
+	      int hostlen;
a85e8e
+	      int port;
a85e8e
+	      int rc = extract_url_info ((const char *)opt->option_data,
a85e8e
+					 (grub_size_t)len,
a85e8e
+					 &scheme, &userinfo, &host, &port,
a85e8e
+					 &file;;
a85e8e
+	      if (rc < 0)
a85e8e
+		continue;
a85e8e
+
a85e8e
+	      /* right now this only handles tftp. */
a85e8e
+	      if (grub_strcmp("tftp", scheme))
a85e8e
+		{
a85e8e
+		  grub_free (scheme);
a85e8e
+		  grub_free (userinfo);
a85e8e
+		  grub_free (host);
a85e8e
+		  grub_free (file);
a85e8e
+		  continue;
a85e8e
+		}
a85e8e
+	      grub_free (userinfo);
a85e8e
+
a85e8e
+	      hostlen = grub_strlen (host);
a85e8e
+	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
a85e8e
+		{
a85e8e
+		  tmp = host+1;
a85e8e
+		  host[hostlen-1] = '\0';
a85e8e
+		}
a85e8e
+	      else
a85e8e
+		tmp = host;
a85e8e
+
a85e8e
+	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
a85e8e
+	      grub_free (scheme);
a85e8e
+	      grub_free (host);
a85e8e
+
a85e8e
+	      if (file && *file)
a85e8e
+		{
a85e8e
+		  tmp = grub_strrchr (file, '/');
a85e8e
+		  if (tmp)
a85e8e
+		    *(tmp+1) = '\0';
a85e8e
+		  else
a85e8e
+		    file[0] = '\0';
a85e8e
+		}
a85e8e
+	      else if (!file)
a85e8e
+		file = grub_strdup ("");
a85e8e
+
a85e8e
+	      if (file[0] == '/')
a85e8e
+		{
a85e8e
+		  *path = grub_strdup (file+1);
a85e8e
+		  grub_free (file);
a85e8e
+		}
a85e8e
+	      else
a85e8e
+		*path = file;
a85e8e
+	    }
a85e8e
+	  else if (num == GRUB_NET_DHCP6_IA_NA)
a85e8e
+	    {
a85e8e
+	      const grub_net_dhcpv6_option_t *ia_na_opt;
a85e8e
+	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
a85e8e
+		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
a85e8e
+	      unsigned int left = len - OFFSET_OF (options, ia_na);
a85e8e
+	      unsigned int j;
a85e8e
+
a85e8e
+	      if ((grub_uint8_t *)ia_na + left >
a85e8e
+		  (grub_uint8_t *)options + option_max)
a85e8e
+		left -= ((grub_uint8_t *)ia_na + left)
a85e8e
+		        - ((grub_uint8_t *)options + option_max);
a85e8e
+
a85e8e
+	      if (len < OFFSET_OF (option_data, opt)
a85e8e
+			+ sizeof (grub_net_dhcpv6_option_t))
a85e8e
+		{
a85e8e
+		  grub_dprintf ("net",
a85e8e
+				"found dhcpv6 ia_na option with no address\n");
a85e8e
+		  continue;
a85e8e
+		}
a85e8e
+
a85e8e
+	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
a85e8e
+		{
a85e8e
+		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
a85e8e
+			       (ia_na->options + j);
a85e8e
+		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
a85e8e
+
a85e8e
+		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
a85e8e
+		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
a85e8e
+		  if (ia_na_opt_len == 0)
a85e8e
+		    break;
a85e8e
+		  if (j + ia_na_opt_len > left)
a85e8e
+		    break;
a85e8e
+		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
a85e8e
+		    {
a85e8e
+		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
a85e8e
+
a85e8e
+		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
a85e8e
+				 ia_na_opt;
a85e8e
+		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
a85e8e
+		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
a85e8e
+				  sizeof (ia_addr->ipv6_address));
a85e8e
+		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
a85e8e
+		    }
a85e8e
+
a85e8e
+		  j += ia_na_opt_len;
a85e8e
+		  left -= ia_na_opt_len;
a85e8e
+		}
a85e8e
+	    }
a85e8e
+
a85e8e
+	  i += len + 4;
a85e8e
+	}
a85e8e
+
a85e8e
+      grub_print_error ();
a85e8e
+    }
a85e8e
+
a85e8e
+  if (is_def)
a85e8e
+    {
a85e8e
+      grub_env_set ("net_default_interface", name);
a85e8e
+      grub_env_export ("net_default_interface");
a85e8e
+    }
a85e8e
+
a85e8e
+    if (inter)
a85e8e
+      grub_net_add_ipv6_local (inter, mask);
a85e8e
+    return inter;
a85e8e
+}
a85e8e
+
a85e8e
+
a85e8e
 void
a85e8e
 grub_net_process_dhcp (struct grub_net_buff *nb,
a85e8e
 		       struct grub_net_card *card)
a85e8e
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
d41074
index 3f112438a93..d7befb2ba9b 100644
a85e8e
--- a/grub-core/net/drivers/efi/efinet.c
a85e8e
+++ b/grub-core/net/drivers/efi/efinet.c
a85e8e
@@ -18,11 +18,15 @@
a85e8e
 
a85e8e
 #include <grub/net/netbuff.h>
a85e8e
 #include <grub/dl.h>
a85e8e
+#include <grub/env.h>
a85e8e
 #include <grub/net.h>
a85e8e
+#include <grub/net/url.h>
a85e8e
 #include <grub/time.h>
a85e8e
 #include <grub/efi/api.h>
a85e8e
 #include <grub/efi/efi.h>
a85e8e
 #include <grub/i18n.h>
a85e8e
+#include <grub/lib/hexdump.h>
a85e8e
+#include <grub/types.h>
a85e8e
 
a85e8e
 GRUB_MOD_LICENSE ("GPLv3+");
a85e8e
 
a85e8e
@@ -339,7 +343,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
a85e8e
 			  char **path)
a85e8e
 {
a85e8e
   struct grub_net_card *card;
a85e8e
-  grub_efi_device_path_t *dp;
a85e8e
+  grub_efi_device_path_t *dp, *ldp = NULL;
a85e8e
 
a85e8e
   dp = grub_efi_get_device_path (hnd);
a85e8e
   if (! dp)
a85e8e
@@ -350,14 +354,19 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
a85e8e
     grub_efi_device_path_t *cdp;
a85e8e
     struct grub_efi_pxe *pxe;
a85e8e
     struct grub_efi_pxe_mode *pxe_mode;
a85e8e
+
a85e8e
     if (card->driver != &efidriver)
a85e8e
       continue;
a85e8e
+
a85e8e
     cdp = grub_efi_get_device_path (card->efi_handle);
a85e8e
     if (! cdp)
a85e8e
       continue;
a85e8e
+
a85e8e
+    ldp = grub_efi_find_last_device_path (dp);
a85e8e
+
a85e8e
     if (grub_efi_compare_device_paths (dp, cdp) != 0)
a85e8e
       {
a85e8e
-	grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
a85e8e
+	grub_efi_device_path_t *dup_dp, *dup_ldp;
a85e8e
 	int match;
a85e8e
 
a85e8e
 	/* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
a85e8e
@@ -366,7 +375,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
a85e8e
 	   devices. We skip them when enumerating cards, so here we need to
a85e8e
 	   find matching MAC device.
a85e8e
          */
a85e8e
-	ldp = grub_efi_find_last_device_path (dp);
a85e8e
 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
a85e8e
 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
a85e8e
 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
a85e8e
@@ -383,16 +391,44 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
a85e8e
 	if (!match)
a85e8e
 	  continue;
a85e8e
       }
a85e8e
+
a85e8e
     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
a85e8e
 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
a85e8e
     if (! pxe)
a85e8e
       continue;
a85e8e
+
a85e8e
     pxe_mode = pxe->mode;
a85e8e
-    grub_net_configure_by_dhcp_ack (card->name, card, 0,
a85e8e
-				    (struct grub_net_bootp_packet *)
a85e8e
-				    &pxe_mode->dhcp_ack,
a85e8e
-				    sizeof (pxe_mode->dhcp_ack),
a85e8e
-				    1, device, path);
a85e8e
+    if (pxe_mode->using_ipv6)
a85e8e
+      {
a85e8e
+	grub_net_link_level_address_t hwaddr;
a85e8e
+
a85e8e
+	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
a85e8e
+	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
a85e8e
+		      pxe_mode->dhcp_ack_received ? "yes" : "no",
a85e8e
+		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
a85e8e
+	if (!pxe_mode->dhcp_ack_received)
a85e8e
+	  continue;
a85e8e
+
a85e8e
+	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
a85e8e
+	grub_memcpy (hwaddr.mac,
a85e8e
+		     card->efi_net->mode->current_address,
a85e8e
+		     sizeof (hwaddr.mac));
a85e8e
+
a85e8e
+	grub_net_configure_by_dhcpv6_ack (card->name, card, 0,
a85e8e
+					  &hwaddr, &pxe_mode->dhcp_ack,
a85e8e
+					  1, device, path);
a85e8e
+	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
a85e8e
+      }
a85e8e
+    else
a85e8e
+      {
a85e8e
+	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
a85e8e
+	grub_net_configure_by_dhcp_ack (card->name, card, 0,
a85e8e
+					(struct grub_net_bootp_packet *)
a85e8e
+					&pxe_mode->dhcp_ack,
a85e8e
+					sizeof (pxe_mode->dhcp_ack),
a85e8e
+					1, device, path);
a85e8e
+	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
a85e8e
+      }
a85e8e
     return;
a85e8e
   }
a85e8e
 }
a85e8e
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
d41074
index b10addbe27b..81d3b6208cb 100644
a85e8e
--- a/grub-core/net/net.c
a85e8e
+++ b/grub-core/net/net.c
a85e8e
@@ -969,6 +969,73 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
a85e8e
   grub_net_network_level_interfaces = inter;
a85e8e
 }
a85e8e
 
a85e8e
+int
a85e8e
+grub_ipv6_get_masksize(grub_uint8_t *be_mask)
a85e8e
+{
a85e8e
+  grub_uint8_t *mask;
a85e8e
+  grub_uint16_t mask16[8];
a85e8e
+  unsigned int x;
a85e8e
+  int ret = 0;
a85e8e
+
a85e8e
+  grub_memcpy (mask16, be_mask, sizeof(mask16));
a85e8e
+  for (x = 0; x < 8; x++)
a85e8e
+    mask16[x] = grub_be_to_cpu16 (mask16[x]);
a85e8e
+
a85e8e
+  mask = (grub_uint8_t *)mask16;
a85e8e
+
a85e8e
+  for (x = 15; x > 0; x++)
a85e8e
+    {
a85e8e
+      grub_uint8_t octet = mask[x];
a85e8e
+      while (octet & 0x80)
a85e8e
+	{
a85e8e
+	  ret++;
a85e8e
+	  octet <<= 1;
a85e8e
+	}
a85e8e
+      if (ret)
a85e8e
+	ret += 8 * (15 - x);
a85e8e
+      break;
a85e8e
+    }
a85e8e
+
a85e8e
+  return ret;
a85e8e
+}
a85e8e
+
a85e8e
+grub_err_t
a85e8e
+grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter,
a85e8e
+			 int mask)
a85e8e
+{
a85e8e
+  struct grub_net_route *route;
a85e8e
+
a85e8e
+  if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
a85e8e
+    return 0;
a85e8e
+
a85e8e
+  if (mask == -1)
a85e8e
+      mask = grub_ipv6_get_masksize ((grub_uint8_t *)inter->address.ipv6);
a85e8e
+
a85e8e
+  if (mask == -1)
a85e8e
+    return 0;
a85e8e
+
a85e8e
+  route = grub_zalloc (sizeof (*route));
a85e8e
+  if (!route)
a85e8e
+    return grub_errno;
a85e8e
+
a85e8e
+  route->name = grub_xasprintf ("%s:local", inter->name);
a85e8e
+  if (!route->name)
a85e8e
+    {
a85e8e
+      grub_free (route);
a85e8e
+      return grub_errno;
a85e8e
+    }
a85e8e
+
a85e8e
+  route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
a85e8e
+  grub_memcpy (route->target.ipv6.base, inter->address.ipv6,
a85e8e
+	       sizeof (inter->address.ipv6));
a85e8e
+  route->target.ipv6.masksize = mask;
a85e8e
+  route->is_gateway = 0;
a85e8e
+  route->interface = inter;
a85e8e
+
a85e8e
+  grub_net_route_register (route);
a85e8e
+
a85e8e
+  return 0;
a85e8e
+}
a85e8e
 
a85e8e
 grub_err_t
a85e8e
 grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
a85e8e
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
d41074
index 51736142764..22a4debdcd4 100644
a85e8e
--- a/grub-core/net/tftp.c
a85e8e
+++ b/grub-core/net/tftp.c
a85e8e
@@ -370,18 +370,22 @@ tftp_open (struct grub_file *file, const char *filename)
a85e8e
   if (!data->pq)
a85e8e
     return grub_errno;
a85e8e
 
a85e8e
+  grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server);
a85e8e
   err = grub_net_resolve_address (file->device->net->server, &addr);
a85e8e
   if (err)
a85e8e
     {
a85e8e
+      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
a85e8e
       destroy_pq (data);
a85e8e
       return err;
a85e8e
     }
a85e8e
 
a85e8e
+  grub_dprintf("tftp", "opening connection\n");
a85e8e
   data->sock = grub_net_udp_open (addr,
a85e8e
 				  TFTP_SERVER_PORT, tftp_receive,
a85e8e
 				  file);
a85e8e
   if (!data->sock)
a85e8e
     {
a85e8e
+      grub_dprintf("tftp", "connection failed\n");
a85e8e
       destroy_pq (data);
a85e8e
       return grub_errno;
a85e8e
     }
a85e8e
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
d41074
index a6cce6e3395..9422ba9a9db 100644
a85e8e
--- a/include/grub/efi/api.h
a85e8e
+++ b/include/grub/efi/api.h
a85e8e
@@ -527,10 +527,16 @@ typedef void *grub_efi_handle_t;
a85e8e
 typedef void *grub_efi_event_t;
a85e8e
 typedef grub_efi_uint64_t grub_efi_lba_t;
a85e8e
 typedef grub_efi_uintn_t grub_efi_tpl_t;
a85e8e
-typedef grub_uint8_t grub_efi_mac_address_t[32];
a85e8e
-typedef grub_uint8_t grub_efi_ipv4_address_t[4];
a85e8e
-typedef grub_uint16_t grub_efi_ipv6_address_t[8];
a85e8e
-typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4)));
a85e8e
+typedef grub_efi_uint8_t grub_efi_mac_address_t[32];
a85e8e
+typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4];
a85e8e
+typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16];
a85e8e
+typedef union
a85e8e
+{
a85e8e
+  grub_efi_uint32_t addr[4];
a85e8e
+  grub_efi_ipv4_address_t v4;
a85e8e
+  grub_efi_ipv6_address_t v6;
a85e8e
+} grub_efi_ip_address_t __attribute__ ((aligned(4)));
a85e8e
+
a85e8e
 typedef grub_efi_uint64_t grub_efi_physical_address_t;
a85e8e
 typedef grub_efi_uint64_t grub_efi_virtual_address_t;
a85e8e
 
a85e8e
@@ -1405,16 +1411,127 @@ struct grub_efi_simple_text_output_interface
a85e8e
 };
a85e8e
 typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t;
a85e8e
 
a85e8e
-typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
a85e8e
+typedef struct grub_efi_pxe_dhcpv4_packet
a85e8e
+{
a85e8e
+  grub_efi_uint8_t bootp_opcode;
a85e8e
+  grub_efi_uint8_t bootp_hwtype;
a85e8e
+  grub_efi_uint8_t bootp_hwaddr_len;
a85e8e
+  grub_efi_uint8_t bootp_gate_hops;
a85e8e
+  grub_efi_uint32_t bootp_ident;
a85e8e
+  grub_efi_uint16_t bootp_seconds;
a85e8e
+  grub_efi_uint16_t bootp_flags;
a85e8e
+  grub_efi_uint8_t bootp_ci_addr[4];
a85e8e
+  grub_efi_uint8_t bootp_yi_addr[4];
a85e8e
+  grub_efi_uint8_t bootp_si_addr[4];
a85e8e
+  grub_efi_uint8_t bootp_gi_addr[4];
a85e8e
+  grub_efi_uint8_t bootp_hw_addr[16];
a85e8e
+  grub_efi_uint8_t bootp_srv_name[64];
a85e8e
+  grub_efi_uint8_t bootp_boot_file[128];
a85e8e
+  grub_efi_uint32_t dhcp_magik;
a85e8e
+  grub_efi_uint8_t dhcp_options[56];
a85e8e
+} grub_efi_pxe_dhcpv4_packet_t;
a85e8e
+
a85e8e
+struct grub_efi_pxe_dhcpv6_packet
a85e8e
+{
a85e8e
+  grub_efi_uint32_t message_type:8;
a85e8e
+  grub_efi_uint32_t transaction_id:24;
a85e8e
+  grub_efi_uint8_t dhcp_options[1024];
a85e8e
+} GRUB_PACKED;
a85e8e
+typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t;
a85e8e
+
a85e8e
+typedef union
a85e8e
+{
a85e8e
+  grub_efi_uint8_t raw[1472];
a85e8e
+  grub_efi_pxe_dhcpv4_packet_t dhcpv4;
a85e8e
+  grub_efi_pxe_dhcpv6_packet_t dhcpv6;
a85e8e
+} grub_efi_pxe_packet_t;
a85e8e
+
a85e8e
+#define GRUB_EFI_PXE_MAX_IPCNT 8
a85e8e
+#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
a85e8e
+#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
a85e8e
+
a85e8e
+typedef struct grub_efi_pxe_ip_filter
a85e8e
+{
a85e8e
+  grub_efi_uint8_t filters;
a85e8e
+  grub_efi_uint8_t ip_count;
a85e8e
+  grub_efi_uint8_t reserved;
a85e8e
+  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
a85e8e
+} grub_efi_pxe_ip_filter_t;
a85e8e
+
a85e8e
+typedef struct grub_efi_pxe_arp_entry
a85e8e
+{
a85e8e
+  grub_efi_ip_address_t ip_addr;
a85e8e
+  grub_efi_mac_address_t mac_addr;
a85e8e
+} grub_efi_pxe_arp_entry_t;
a85e8e
+
a85e8e
+typedef struct grub_efi_pxe_route_entry
a85e8e
+{
a85e8e
+  grub_efi_ip_address_t ip_addr;
a85e8e
+  grub_efi_ip_address_t subnet_mask;
a85e8e
+  grub_efi_ip_address_t gateway_addr;
a85e8e
+} grub_efi_pxe_route_entry_t;
a85e8e
+
a85e8e
+typedef struct grub_efi_pxe_icmp_error
a85e8e
+{
a85e8e
+  grub_efi_uint8_t type;
a85e8e
+  grub_efi_uint8_t code;
a85e8e
+  grub_efi_uint16_t checksum;
a85e8e
+  union
a85e8e
+    {
a85e8e
+      grub_efi_uint32_t reserved;
a85e8e
+      grub_efi_uint32_t mtu;
a85e8e
+      grub_efi_uint32_t pointer;
a85e8e
+      struct
a85e8e
+	{
a85e8e
+	  grub_efi_uint16_t identifier;
a85e8e
+	  grub_efi_uint16_t sequence;
a85e8e
+	} echo;
a85e8e
+    } u;
a85e8e
+  grub_efi_uint8_t data[494];
a85e8e
+} grub_efi_pxe_icmp_error_t;
a85e8e
+
a85e8e
+typedef struct grub_efi_pxe_tftp_error
a85e8e
+{
a85e8e
+  grub_efi_uint8_t error_code;
a85e8e
+  grub_efi_char8_t error_string[127];
a85e8e
+} grub_efi_pxe_tftp_error_t;
a85e8e
 
a85e8e
 typedef struct grub_efi_pxe_mode
a85e8e
 {
a85e8e
-  grub_uint8_t unused[52];
a85e8e
+  grub_efi_boolean_t started;
a85e8e
+  grub_efi_boolean_t ipv6_available;
a85e8e
+  grub_efi_boolean_t ipv6_supported;
a85e8e
+  grub_efi_boolean_t using_ipv6;
a85e8e
+  grub_efi_boolean_t bis_supported;
a85e8e
+  grub_efi_boolean_t bis_detected;
a85e8e
+  grub_efi_boolean_t auto_arp;
a85e8e
+  grub_efi_boolean_t send_guid;
a85e8e
+  grub_efi_boolean_t dhcp_discover_valid;
a85e8e
+  grub_efi_boolean_t dhcp_ack_received;
a85e8e
+  grub_efi_boolean_t proxy_offer_received;
a85e8e
+  grub_efi_boolean_t pxe_discover_valid;
a85e8e
+  grub_efi_boolean_t pxe_reply_received;
a85e8e
+  grub_efi_boolean_t pxe_bis_reply_received;
a85e8e
+  grub_efi_boolean_t icmp_error_received;
a85e8e
+  grub_efi_boolean_t tftp_error_received;
a85e8e
+  grub_efi_boolean_t make_callbacks;
a85e8e
+  grub_efi_uint8_t ttl;
a85e8e
+  grub_efi_uint8_t tos;
a85e8e
+  grub_efi_ip_address_t station_ip;
a85e8e
+  grub_efi_ip_address_t subnet_mask;
a85e8e
   grub_efi_pxe_packet_t dhcp_discover;
a85e8e
   grub_efi_pxe_packet_t dhcp_ack;
a85e8e
   grub_efi_pxe_packet_t proxy_offer;
a85e8e
   grub_efi_pxe_packet_t pxe_discover;
a85e8e
   grub_efi_pxe_packet_t pxe_reply;
a85e8e
+  grub_efi_pxe_packet_t pxe_bis_reply;
a85e8e
+  grub_efi_pxe_ip_filter_t ip_filter;
a85e8e
+  grub_efi_uint32_t arp_cache_entries;
a85e8e
+  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
a85e8e
+  grub_efi_uint32_t route_table_entries;
a85e8e
+  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
a85e8e
+  grub_efi_pxe_icmp_error_t icmp_error;
a85e8e
+  grub_efi_pxe_tftp_error_t tftp_error;
a85e8e
 } grub_efi_pxe_mode_t;
a85e8e
 
a85e8e
 typedef struct grub_efi_pxe
a85e8e
diff --git a/include/grub/net.h b/include/grub/net.h
d41074
index 88fc71ceffe..c7b8e2ac885 100644
a85e8e
--- a/include/grub/net.h
a85e8e
+++ b/include/grub/net.h
a85e8e
@@ -418,6 +418,51 @@ struct grub_net_bootp_packet
a85e8e
   grub_uint8_t vendor[0];
a85e8e
 } GRUB_PACKED;
a85e8e
 
a85e8e
+enum
a85e8e
+  {
a85e8e
+    GRUB_NET_DHCP6_IA_NA = 3,
a85e8e
+    GRUB_NET_DHCP6_IA_ADDRESS = 5,
a85e8e
+    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
a85e8e
+  };
a85e8e
+
a85e8e
+struct grub_net_dhcpv6_option
a85e8e
+{
a85e8e
+  grub_uint16_t option_num;
a85e8e
+  grub_uint16_t option_len;
a85e8e
+  grub_uint8_t option_data[];
a85e8e
+} GRUB_PACKED;
a85e8e
+typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
a85e8e
+
a85e8e
+struct grub_net_dhcpv6_opt_ia_na
a85e8e
+{
a85e8e
+  grub_uint16_t option_num;
a85e8e
+  grub_uint16_t option_len;
a85e8e
+  grub_uint32_t iaid;
a85e8e
+  grub_uint32_t t1;
a85e8e
+  grub_uint32_t t2;
a85e8e
+  grub_uint8_t options[];
a85e8e
+} GRUB_PACKED;
a85e8e
+typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
a85e8e
+
a85e8e
+struct grub_net_dhcpv6_opt_ia_address
a85e8e
+{
a85e8e
+  grub_uint16_t option_num;
a85e8e
+  grub_uint16_t option_len;
a85e8e
+  grub_uint64_t ipv6_address[2];
a85e8e
+  grub_uint32_t preferred_lifetime;
a85e8e
+  grub_uint32_t valid_lifetime;
a85e8e
+  grub_uint8_t options[];
a85e8e
+} GRUB_PACKED;
a85e8e
+typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
a85e8e
+
a85e8e
+struct grub_net_dhcpv6_packet
a85e8e
+{
a85e8e
+  grub_uint32_t message_type:8;
a85e8e
+  grub_uint32_t transaction_id:24;
a85e8e
+  grub_uint8_t dhcp_options[1024];
a85e8e
+} GRUB_PACKED;
a85e8e
+typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
a85e8e
+
a85e8e
 #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
a85e8e
 #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
a85e8e
 #define	GRUB_NET_BOOTP_RFC1048_MAGIC_2	0x53
a85e8e
@@ -446,6 +491,21 @@ grub_net_configure_by_dhcp_ack (const char *name,
a85e8e
 				grub_size_t size,
a85e8e
 				int is_def, char **device, char **path);
a85e8e
 
a85e8e
+struct grub_net_network_level_interface *
a85e8e
+grub_net_configure_by_dhcpv6_ack (const char *name,
a85e8e
+				 struct grub_net_card *card,
a85e8e
+				 grub_net_interface_flags_t flags,
a85e8e
+				 const grub_net_link_level_address_t *hwaddr,
a85e8e
+				 const struct grub_net_dhcpv6_packet *packet,
a85e8e
+				 int is_def, char **device, char **path);
a85e8e
+
a85e8e
+int
a85e8e
+grub_ipv6_get_masksize(grub_uint8_t *mask);
a85e8e
+
a85e8e
+grub_err_t
a85e8e
+grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf,
a85e8e
+			 int mask);
a85e8e
+
a85e8e
 grub_err_t
a85e8e
 grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
a85e8e
 			 int mask);