63f1a9
From 2ba7c6d3c99c669ce20d26fdc9ed7851fc10b6b4 Mon Sep 17 00:00:00 2001
63f1a9
From: Michael Chang <mchang@suse.com>
63f1a9
Date: Wed, 22 Feb 2017 14:27:50 +0800
31cddd
Subject: [PATCH] Support UEFI networking protocols
63f1a9
63f1a9
References: fate#320130, bsc#1015589, bsc#1076132
63f1a9
Patch-Mainline: no
63f1a9
63f1a9
V1:
63f1a9
  * Add preliminary support of UEFI networking protocols
63f1a9
  * Support UEFI HTTPS Boot
63f1a9
63f1a9
V2:
63f1a9
  * Workaround http data access in firmware
63f1a9
  * Fix DNS device path parsing for efinet device
63f1a9
  * Relaxed UEFI Protocol requirement
63f1a9
  * Support Intel OPA (Omni-Path Architecture) PXE Boot
63f1a9
63f1a9
V3:
63f1a9
  * Fix bufio in calculating address of next_buf
63f1a9
  * Check HTTP respond code
63f1a9
  * Use HEAD request method to test before GET
63f1a9
  * Finish HTTP transaction in one go
63f1a9
  * Fix bsc#1076132
63f1a9
---
63f1a9
 grub-core/Makefile.core.def        |   18 +
63f1a9
 grub-core/io/bufio.c               |    2 +-
63f1a9
 grub-core/kern/efi/efi.c           |   96 ++-
63f1a9
 grub-core/net/drivers/efi/efinet.c |   27 +
63f1a9
 grub-core/net/efi/dhcp.c           |  397 ++++++++++
63f1a9
 grub-core/net/efi/efi_netfs.c      |   57 ++
63f1a9
 grub-core/net/efi/http.c           |  419 +++++++++++
63f1a9
 grub-core/net/efi/ip4_config.c     |  398 ++++++++++
63f1a9
 grub-core/net/efi/ip6_config.c     |  422 +++++++++++
63f1a9
 grub-core/net/efi/net.c            | 1428 ++++++++++++++++++++++++++++++++++++
63f1a9
 grub-core/net/efi/pxe.c            |  424 +++++++++++
63f1a9
 grub-core/net/net.c                |   74 ++
63f1a9
 util/grub-mknetdir.c               |   23 +-
63f1a9
 include/grub/efi/api.h             |  161 +++-
63f1a9
 include/grub/efi/dhcp.h            |  343 +++++++++
63f1a9
 include/grub/efi/http.h            |  215 ++++++
63f1a9
 include/grub/net/efi.h             |  144 ++++
63f1a9
 17 files changed, 4621 insertions(+), 27 deletions(-)
63f1a9
 create mode 100644 grub-core/net/efi/dhcp.c
63f1a9
 create mode 100644 grub-core/net/efi/efi_netfs.c
63f1a9
 create mode 100644 grub-core/net/efi/http.c
63f1a9
 create mode 100644 grub-core/net/efi/ip4_config.c
63f1a9
 create mode 100644 grub-core/net/efi/ip6_config.c
63f1a9
 create mode 100644 grub-core/net/efi/net.c
63f1a9
 create mode 100644 grub-core/net/efi/pxe.c
63f1a9
 create mode 100644 include/grub/efi/dhcp.h
63f1a9
 create mode 100644 include/grub/efi/http.h
63f1a9
 create mode 100644 include/grub/net/efi.h
63f1a9
63f1a9
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
63f1a9
index 51f07279d83..95f17b9e310 100644
63f1a9
--- a/grub-core/Makefile.core.def
63f1a9
+++ b/grub-core/Makefile.core.def
63f1a9
@@ -2197,6 +2197,18 @@ module = {
63f1a9
   common = hook/datehook.c;
63f1a9
 };
63f1a9
 
63f1a9
+module = {
63f1a9
+  name = efi_netfs;
63f1a9
+  common = net/efi/efi_netfs.c;
63f1a9
+  common = net/efi/net.c;
63f1a9
+  common = net/efi/http.c;
63f1a9
+  common = net/efi/pxe.c;
63f1a9
+  common = net/efi/ip4_config.c;
63f1a9
+  common = net/efi/ip6_config.c;
63f1a9
+  common = net/efi/dhcp.c;
63f1a9
+  enable = efi;
63f1a9
+};
63f1a9
+
63f1a9
 module = {
63f1a9
   name = net;
63f1a9
   common = net/net.c;
63f1a9
@@ -2211,6 +2223,12 @@ module = {
63f1a9
   common = net/arp.c;
63f1a9
   common = net/netbuff.c;
63f1a9
   common = net/url.c;
63f1a9
+  efi = net/efi/net.c;
63f1a9
+  efi = net/efi/http.c;
63f1a9
+  efi = net/efi/pxe.c;
63f1a9
+  efi = net/efi/ip4_config.c;
63f1a9
+  efi = net/efi/ip6_config.c;
63f1a9
+  efi = net/efi/dhcp.c;
63f1a9
 };
63f1a9
 
63f1a9
 module = {
63f1a9
diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
63f1a9
index 22438277d74..d0b0f71b6ed 100644
63f1a9
--- a/grub-core/io/bufio.c
63f1a9
+++ b/grub-core/io/bufio.c
63f1a9
@@ -132,7 +132,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
63f1a9
     return res;
63f1a9
 
63f1a9
   /* Need to read some more.  */
63f1a9
-  next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1);
63f1a9
+  next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size;
63f1a9
   /* Now read between file->offset + res and bufio->buffer_at.  */
63f1a9
   if (file->offset + res < next_buf)
63f1a9
     {
63f1a9
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
63f1a9
index 621251242e1..d765b5881b9 100644
63f1a9
--- a/grub-core/kern/efi/efi.c
63f1a9
+++ b/grub-core/kern/efi/efi.c
63f1a9
@@ -687,7 +687,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
63f1a9
 	      {
63f1a9
 		grub_efi_ipv4_device_path_t *ipv4
63f1a9
 		  = (grub_efi_ipv4_device_path_t *) dp;
63f1a9
-		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)",
63f1a9
+		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x",
63f1a9
 			     (unsigned) ipv4->local_ip_address[0],
63f1a9
 			     (unsigned) ipv4->local_ip_address[1],
63f1a9
 			     (unsigned) ipv4->local_ip_address[2],
63f1a9
@@ -700,33 +700,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
63f1a9
 			     (unsigned) ipv4->remote_port,
63f1a9
 			     (unsigned) ipv4->protocol,
63f1a9
 			     (unsigned) ipv4->static_ip_address);
63f1a9
+		if (len == sizeof (*ipv4))
63f1a9
+		  {
63f1a9
+		    grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u",
63f1a9
+			(unsigned) ipv4->gateway_ip_address[0],
63f1a9
+			(unsigned) ipv4->gateway_ip_address[1],
63f1a9
+			(unsigned) ipv4->gateway_ip_address[2],
63f1a9
+			(unsigned) ipv4->gateway_ip_address[3],
63f1a9
+			(unsigned) ipv4->subnet_mask[0],
63f1a9
+			(unsigned) ipv4->subnet_mask[1],
63f1a9
+			(unsigned) ipv4->subnet_mask[2],
63f1a9
+			(unsigned) ipv4->subnet_mask[3]);
63f1a9
+		  }
63f1a9
+		grub_printf (")");
63f1a9
 	      }
63f1a9
 	      break;
63f1a9
 	    case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE:
63f1a9
 	      {
63f1a9
 		grub_efi_ipv6_device_path_t *ipv6
63f1a9
 		  = (grub_efi_ipv6_device_path_t *) dp;
63f1a9
-		grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)",
63f1a9
-			     (unsigned) ipv6->local_ip_address[0],
63f1a9
-			     (unsigned) ipv6->local_ip_address[1],
63f1a9
-			     (unsigned) ipv6->local_ip_address[2],
63f1a9
-			     (unsigned) ipv6->local_ip_address[3],
63f1a9
-			     (unsigned) ipv6->local_ip_address[4],
63f1a9
-			     (unsigned) ipv6->local_ip_address[5],
63f1a9
-			     (unsigned) ipv6->local_ip_address[6],
63f1a9
-			     (unsigned) ipv6->local_ip_address[7],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[0],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[1],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[2],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[3],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[4],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[5],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[6],
63f1a9
-			     (unsigned) ipv6->remote_ip_address[7],
63f1a9
+		grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x",
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]),
63f1a9
+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]),
63f1a9
 			     (unsigned) ipv6->local_port,
63f1a9
 			     (unsigned) ipv6->remote_port,
63f1a9
 			     (unsigned) ipv6->protocol,
63f1a9
 			     (unsigned) ipv6->static_ip_address);
63f1a9
+		if (len == sizeof (*ipv6))
63f1a9
+		  {
63f1a9
+		    grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
63f1a9
+			(unsigned) ipv6->prefix_length,
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]),
63f1a9
+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7]));
63f1a9
+		  }
63f1a9
+		grub_printf (")");
63f1a9
 	      }
63f1a9
 	      break;
63f1a9
 	    case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
63f1a9
@@ -766,6 +793,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
63f1a9
 	      dump_vendor_path ("Messaging",
63f1a9
 				(grub_efi_vendor_device_path_t *) dp);
63f1a9
 	      break;
63f1a9
+	    case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE:
63f1a9
+	      {
63f1a9
+		grub_efi_uri_device_path_t *uri
63f1a9
+		  = (grub_efi_uri_device_path_t *) dp;
63f1a9
+		grub_printf ("/URI(%s)", uri->uri);
63f1a9
+	      }
63f1a9
+	      break;
63f1a9
+	    case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE:
63f1a9
+	      {
63f1a9
+		grub_efi_dns_device_path_t *dns
63f1a9
+		  = (grub_efi_dns_device_path_t *) dp;
63f1a9
+		if (dns->is_ipv6)
63f1a9
+		  {
63f1a9
+		    grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)",
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[0]) >> 16),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[0])),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[1]) >> 16),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[1])),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[2]) >> 16),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[2])),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[3]) >> 16),
63f1a9
+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].v4[3])));
63f1a9
+		  }
63f1a9
+		else
63f1a9
+		  {
63f1a9
+		    grub_printf ("/DNS(%d.%d.%d.%d)",
63f1a9
+			  dns->dns_server_ip[0].v4[0],
63f1a9
+			  dns->dns_server_ip[0].v4[1],
63f1a9
+			  dns->dns_server_ip[0].v4[2],
63f1a9
+			  dns->dns_server_ip[0].v4[3]);
63f1a9
+		  }
63f1a9
+	      }
63f1a9
+	      break;
63f1a9
 	    default:
63f1a9
 	      grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype);
63f1a9
 	      break;
63f1a9
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
63f1a9
index 64d3019af67..eed6f587ae3 100644
63f1a9
--- a/grub-core/net/drivers/efi/efinet.c
63f1a9
+++ b/grub-core/net/drivers/efi/efinet.c
63f1a9
@@ -28,6 +28,7 @@
63f1a9
 #include <grub/lib/hexdump.h>
63f1a9
 #include <grub/types.h>
63f1a9
 #include <grub/net/netbuff.h>
63f1a9
+#include <grub/env.h>
63f1a9
 
63f1a9
 GRUB_MOD_LICENSE ("GPLv3+");
63f1a9
 
63f1a9
@@ -565,6 +566,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
63f1a9
 
63f1a9
   ldp = grub_efi_find_last_device_path (ddp);
63f1a9
 
63f1a9
+  /* Skip the DNS Device */
63f1a9
+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
63f1a9
+      && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
63f1a9
+    {
63f1a9
+      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
63f1a9
+      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
63f1a9
+      ldp->length = sizeof (*ldp);
63f1a9
+
63f1a9
+      ldp = grub_efi_find_last_device_path (ddp);
63f1a9
+    }
63f1a9
+
63f1a9
   if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
63f1a9
       || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
63f1a9
           && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
63f1a9
@@ -834,6 +846,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
63f1a9
 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
63f1a9
 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
63f1a9
 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
63f1a9
+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE
63f1a9
 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
63f1a9
 	  continue;
63f1a9
 	dup_dp = grub_efi_duplicate_device_path (dp);
63f1a9
@@ -848,6 +861,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
63f1a9
 	    dup_ldp->length = sizeof (*dup_ldp);
63f1a9
 	  }
63f1a9
 
63f1a9
+	dup_ldp = grub_efi_find_last_device_path (dup_dp);
63f1a9
+	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
63f1a9
+	  {
63f1a9
+	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
63f1a9
+	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
63f1a9
+	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
63f1a9
+	    dup_ldp->length = sizeof (*dup_ldp);
63f1a9
+	  }
63f1a9
+
63f1a9
 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
63f1a9
 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
63f1a9
 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
63f1a9
@@ -917,6 +939,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
63f1a9
 
63f1a9
 GRUB_MOD_INIT(efinet)
63f1a9
 {
63f1a9
+  if (grub_efi_net_config)
63f1a9
+    return;
63f1a9
+
63f1a9
   grub_efinet_findcards ();
63f1a9
   grub_efi_net_config = grub_efi_net_config_real;
63f1a9
 }
63f1a9
@@ -928,5 +953,7 @@ GRUB_MOD_FINI(efinet)
63f1a9
   FOR_NET_CARDS_SAFE (card, next) 
63f1a9
     if (card->driver == &efidriver)
63f1a9
       grub_net_card_unregister (card);
63f1a9
+
63f1a9
+  grub_efi_net_config = NULL;
63f1a9
 }
63f1a9
 
63f1a9
diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
63f1a9
new file mode 100644
63f1a9
index 00000000000..dbef63d8c08
63f1a9
--- /dev/null
63f1a9
+++ b/grub-core/net/efi/dhcp.c
63f1a9
@@ -0,0 +1,397 @@
63f1a9
+#include <grub/mm.h>
63f1a9
+#include <grub/command.h>
63f1a9
+#include <grub/efi/api.h>
63f1a9
+#include <grub/efi/efi.h>
63f1a9
+#include <grub/misc.h>
63f1a9
+#include <grub/net/efi.h>
63f1a9
+#include <grub/charset.h>
63f1a9
+
63f1a9
+#ifdef GRUB_EFI_NET_DEBUG
63f1a9
+static void
63f1a9
+dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode)
63f1a9
+{
63f1a9
+    switch (mode->state)
63f1a9
+      {
63f1a9
+	case GRUB_EFI_DHCP4_STOPPED:
63f1a9
+	  grub_printf ("STATE: STOPPED\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_INIT:
63f1a9
+	  grub_printf ("STATE: INIT\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_SELECTING:
63f1a9
+	  grub_printf ("STATE: SELECTING\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_REQUESTING:
63f1a9
+	  grub_printf ("STATE: REQUESTING\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_BOUND:
63f1a9
+	  grub_printf ("STATE: BOUND\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_RENEWING:
63f1a9
+	  grub_printf ("STATE: RENEWING\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_REBINDING:
63f1a9
+	  grub_printf ("STATE: REBINDING\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_INIT_REBOOT:
63f1a9
+	  grub_printf ("STATE: INIT_REBOOT\n");
63f1a9
+	  break;
63f1a9
+	case GRUB_EFI_DHCP4_REBOOTING:
63f1a9
+	  grub_printf ("STATE: REBOOTING\n");
63f1a9
+	  break;
63f1a9
+	default:
63f1a9
+	  grub_printf ("STATE: UNKNOWN\n");
63f1a9
+	  break;
63f1a9
+      }
63f1a9
+
63f1a9
+    grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n",
63f1a9
+      mode->client_address[0],
63f1a9
+      mode->client_address[1],
63f1a9
+      mode->client_address[2],
63f1a9
+      mode->client_address[3]);
63f1a9
+    grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n",
63f1a9
+      mode->server_address[0],
63f1a9
+      mode->server_address[1],
63f1a9
+      mode->server_address[2],
63f1a9
+      mode->server_address[3]);
63f1a9
+    grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n",
63f1a9
+      mode->subnet_mask[0],
63f1a9
+      mode->subnet_mask[1],
63f1a9
+      mode->subnet_mask[2],
63f1a9
+      mode->subnet_mask[3]);
63f1a9
+    grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n",
63f1a9
+      mode->router_address[0],
63f1a9
+      mode->router_address[1],
63f1a9
+      mode->router_address[2],
63f1a9
+      mode->router_address[3]);
63f1a9
+}
63f1a9
+#endif
63f1a9
+
63f1a9
+static grub_efi_ipv4_address_t *
63f1a9
+grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet)
63f1a9
+{
63f1a9
+  grub_efi_dhcp4_packet_option_t **option_list;
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_uint32_t option_count = 0;
63f1a9
+  grub_efi_uint32_t i;
63f1a9
+
63f1a9
+  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_BUFFER_TOO_SMALL)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  option_list = grub_malloc (option_count * sizeof(*option_list));
63f1a9
+  if (!option_list)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list);
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_free (option_list);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  for (i = 0; i < option_count; ++i)
63f1a9
+    {
63f1a9
+      if (option_list[i]->op_code == 6)
63f1a9
+	{
63f1a9
+	  grub_efi_ipv4_address_t *dns_address;
63f1a9
+
63f1a9
+	  if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0))
63f1a9
+	    continue;
63f1a9
+
63f1a9
+	  /* We only contact primary dns */
63f1a9
+	  dns_address = grub_malloc (sizeof (*dns_address));
63f1a9
+	  if (!dns_address)
63f1a9
+	    {
63f1a9
+	      grub_free (option_list);
63f1a9
+	      return NULL;
63f1a9
+	    }
63f1a9
+	  grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address));
63f1a9
+	  grub_free (option_list);
63f1a9
+	  return dns_address;
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  grub_free (option_list);
63f1a9
+  return NULL;
63f1a9
+}
63f1a9
+
63f1a9
+#if 0
63f1a9
+/* Somehow this doesn't work ... */
63f1a9
+static grub_err_t
63f1a9
+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
63f1a9
+		    int argc __attribute__ ((unused)),
63f1a9
+		    char **args __attribute__ ((unused)))
63f1a9
+{
63f1a9
+  struct grub_efi_net_device *dev;
63f1a9
+  for (dev = net_devices; dev; dev = dev->next)
63f1a9
+    {
63f1a9
+      grub_efi_pxe_t *pxe = dev->ip4_pxe;
63f1a9
+      grub_efi_pxe_mode_t *mode = pxe->mode;
63f1a9
+      grub_efi_status_t status;
63f1a9
+
63f1a9
+      if (!mode->started)
63f1a9
+	{
63f1a9
+	  status = efi_call_2 (pxe->start, pxe, 0);
63f1a9
+
63f1a9
+	  if (status != GRUB_EFI_SUCCESS)
63f1a9
+	      grub_printf ("Couldn't start PXE\n");
63f1a9
+	}
63f1a9
+
63f1a9
+      status = efi_call_2 (pxe->dhcp, pxe, 0);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+
63f1a9
+      dev->prefer_ip6 = 0;
63f1a9
+    }
63f1a9
+
63f1a9
+  return GRUB_ERR_NONE;
63f1a9
+}
63f1a9
+#endif
63f1a9
+
63f1a9
+static grub_err_t
63f1a9
+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
63f1a9
+		    int argc,
63f1a9
+		    char **args)
63f1a9
+{
63f1a9
+  struct grub_efi_net_device *netdev;
63f1a9
+
63f1a9
+  for (netdev = net_devices; netdev; netdev = netdev->next)
63f1a9
+    {
63f1a9
+      grub_efi_status_t status;
63f1a9
+      grub_efi_dhcp4_mode_data_t mode;
63f1a9
+      grub_efi_dhcp4_config_data_t config;
63f1a9
+      grub_efi_dhcp4_packet_option_t *options;
63f1a9
+      grub_efi_ipv4_address_t *dns_address;
63f1a9
+      grub_efi_net_ip_manual_address_t net_ip;
63f1a9
+      grub_efi_net_ip_address_t ip_addr;
63f1a9
+      grub_efi_net_interface_t *inf = NULL;
63f1a9
+
63f1a9
+      if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0)
63f1a9
+	continue;
63f1a9
+
63f1a9
+      grub_memset (&config, 0, sizeof(config));
63f1a9
+
63f1a9
+      config.option_count = 1;
63f1a9
+      options = grub_malloc (sizeof(*options) + 2);
63f1a9
+      /* Parameter request list */
63f1a9
+      options->op_code = 55;
63f1a9
+      options->length = 3;
63f1a9
+      /* subnet mask */
63f1a9
+      options->data[0] = 1;
63f1a9
+      /* router */
63f1a9
+      options->data[1] = 3;
63f1a9
+      /* DNS */
63f1a9
+      options->data[2] = 6;
63f1a9
+      config.option_list = &options;
63f1a9
+
63f1a9
+      /* FIXME: What if the dhcp has bounded */
63f1a9
+      status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config);
63f1a9
+      grub_free (options);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+
63f1a9
+      status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp4 start failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+
63f1a9
+      status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+
63f1a9
+#ifdef GRUB_EFI_NET_DEBUG
63f1a9
+      dhcp4_mode_print (&mode);
63f1a9
+#endif
63f1a9
+
63f1a9
+      for (inf = netdev->net_interfaces; inf; inf = inf->next)
63f1a9
+	if (inf->prefer_ip6 == 0)
63f1a9
+	  break;
63f1a9
+
63f1a9
+      grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address));
63f1a9
+      grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask));
63f1a9
+
63f1a9
+      if (!inf)
63f1a9
+	{
63f1a9
+	  char *name = grub_xasprintf ("%s:dhcp", netdev->card_name);
63f1a9
+
63f1a9
+	  net_ip.is_ip6 = 0;
63f1a9
+	  inf = grub_efi_net_create_interface (netdev,
63f1a9
+		    name,
63f1a9
+		    &net_ip,
63f1a9
+		    1);
63f1a9
+	  grub_free (name);
63f1a9
+	}
63f1a9
+      else
63f1a9
+	{
63f1a9
+	  efi_net_interface_set_address (inf, &net_ip, 1);
63f1a9
+	}
63f1a9
+
63f1a9
+      grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4));
63f1a9
+      efi_net_interface_set_gateway (inf, &ip_addr);
63f1a9
+
63f1a9
+      dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet);
63f1a9
+      if (dns_address)
63f1a9
+	efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address);
63f1a9
+
63f1a9
+    }
63f1a9
+
63f1a9
+  return GRUB_ERR_NONE;
63f1a9
+}
63f1a9
+
63f1a9
+
63f1a9
+static grub_err_t
63f1a9
+grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
63f1a9
+		    int argc,
63f1a9
+		    char **args)
63f1a9
+{
63f1a9
+  struct grub_efi_net_device *dev;
63f1a9
+  grub_efi_uint32_t ia_id;
63f1a9
+
63f1a9
+  for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++)
63f1a9
+    {
63f1a9
+      grub_efi_dhcp6_config_data_t config;
63f1a9
+      grub_efi_dhcp6_packet_option_t *option_list[1];
63f1a9
+      grub_efi_dhcp6_packet_option_t *opt;
63f1a9
+      grub_efi_status_t status;
63f1a9
+      grub_efi_dhcp6_mode_data_t mode;
63f1a9
+      grub_efi_dhcp6_retransmission_t retrans;
63f1a9
+      grub_efi_net_ip_manual_address_t net_ip;
63f1a9
+      grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
63f1a9
+      grub_efi_net_interface_t *inf = NULL;
63f1a9
+
63f1a9
+      if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0)
63f1a9
+	continue;
63f1a9
+
63f1a9
+      opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t));
63f1a9
+
63f1a9
+#define GRUB_EFI_DHCP6_OPT_ORO 6
63f1a9
+
63f1a9
+      opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO);
63f1a9
+      opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t));
63f1a9
+
63f1a9
+#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59
63f1a9
+#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23
63f1a9
+
63f1a9
+      grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL));
63f1a9
+      grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t),
63f1a9
+	      grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS));
63f1a9
+
63f1a9
+      option_list[0] = opt;
63f1a9
+      retrans.irt = 4;
63f1a9
+      retrans.mrc = 4;
63f1a9
+      retrans.mrt = 32;
63f1a9
+      retrans.mrd = 60;
63f1a9
+
63f1a9
+      config.dhcp6_callback = NULL;
63f1a9
+      config.callback_context = NULL;
63f1a9
+      config.option_count = 1;
63f1a9
+      config.option_list = option_list;
63f1a9
+      config.ia_descriptor.ia_id = ia_id;
63f1a9
+      config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA;
63f1a9
+      config.ia_info_event = NULL;
63f1a9
+      config.reconfigure_accept = 0;
63f1a9
+      config.rapid_commit = 0;
63f1a9
+      config.solicit_retransmission = &retrans;
63f1a9
+
63f1a9
+      status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config);
63f1a9
+      grub_free (opt);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp6 configure failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+      status = efi_call_1 (dev->dhcp6->start, dev->dhcp6);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp6 start failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+
63f1a9
+      status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+
63f1a9
+      for (inf = dev->net_interfaces; inf; inf = inf->next)
63f1a9
+	if (inf->prefer_ip6 == 1)
63f1a9
+	  break;
63f1a9
+
63f1a9
+      grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address));
63f1a9
+      net_ip.ip6.prefix_length = 64;
63f1a9
+      net_ip.ip6.is_anycast = 0;
63f1a9
+      net_ip.is_ip6 = 1;
63f1a9
+
63f1a9
+      if (!inf)
63f1a9
+	{
63f1a9
+	  char *name = grub_xasprintf ("%s:dhcp", dev->card_name);
63f1a9
+
63f1a9
+	  inf = grub_efi_net_create_interface (dev,
63f1a9
+		    name,
63f1a9
+		    &net_ip,
63f1a9
+		    1);
63f1a9
+	  grub_free (name);
63f1a9
+	}
63f1a9
+      else
63f1a9
+	{
63f1a9
+	  efi_net_interface_set_address (inf, &net_ip, 1);
63f1a9
+	}
63f1a9
+
63f1a9
+      {
63f1a9
+	grub_efi_uint32_t count = 0;
63f1a9
+	grub_efi_dhcp6_packet_option_t **options = NULL;
63f1a9
+	grub_efi_uint32_t i;
63f1a9
+
63f1a9
+	status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL);
63f1a9
+
63f1a9
+	if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
63f1a9
+	  {
63f1a9
+	    options = grub_malloc (count * sizeof(*options));
63f1a9
+	    status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
63f1a9
+	  }
63f1a9
+
63f1a9
+	if (status != GRUB_EFI_SUCCESS)
63f1a9
+	  {
63f1a9
+	    if (options)
63f1a9
+	      grub_free (options);
63f1a9
+	    continue;
63f1a9
+	  }
63f1a9
+
63f1a9
+	for (i = 0; i < count; ++i)
63f1a9
+	  {
63f1a9
+	    if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS))
63f1a9
+	      {
63f1a9
+		grub_efi_net_ip_address_t dns;
63f1a9
+		grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6));
63f1a9
+		efi_net_interface_set_dns (inf, &dns);
63f1a9
+		break;
63f1a9
+	      }
63f1a9
+	  }
63f1a9
+
63f1a9
+	if (options)
63f1a9
+	  grub_free (options);
63f1a9
+      }
63f1a9
+
63f1a9
+      efi_call_1 (b->free_pool, mode.client_id);
63f1a9
+      efi_call_1 (b->free_pool, mode.ia);
63f1a9
+    }
63f1a9
+
63f1a9
+  return GRUB_ERR_NONE;
63f1a9
+}
63f1a9
+
63f1a9
+grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp;
63f1a9
+grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6;
63f1a9
diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c
63f1a9
new file mode 100644
63f1a9
index 00000000000..ef371d885ea
63f1a9
--- /dev/null
63f1a9
+++ b/grub-core/net/efi/efi_netfs.c
63f1a9
@@ -0,0 +1,57 @@
63f1a9
+#include <grub/dl.h>
63f1a9
+#include <grub/env.h>
63f1a9
+#define EFI_NET_CMD_PREFIX "net_efi"
63f1a9
+#include <grub/net/efi.h>
63f1a9
+
63f1a9
+GRUB_MOD_LICENSE ("GPLv3+");
63f1a9
+
63f1a9
+static grub_command_t cmd_efi_lsroutes;
63f1a9
+static grub_command_t cmd_efi_lscards;
63f1a9
+static grub_command_t cmd_efi_lsaddrs;
63f1a9
+static grub_command_t cmd_efi_addaddr;
63f1a9
+static grub_command_t cmd_efi_bootp;
63f1a9
+static grub_command_t cmd_efi_bootp6;
63f1a9
+
63f1a9
+static int initialized;
63f1a9
+
63f1a9
+GRUB_MOD_INIT(efi_netfs)
63f1a9
+{
63f1a9
+  if (grub_net_open)
63f1a9
+    return;
63f1a9
+
63f1a9
+  if (grub_efi_net_fs_init ())
63f1a9
+    {
63f1a9
+      cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes,
63f1a9
+					    "", N_("list network routes"));
63f1a9
+      cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards,
63f1a9
+					   "", N_("list network cards"));
63f1a9
+      cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs,
63f1a9
+					  "", N_("list network addresses"));
63f1a9
+      cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr,
63f1a9
+					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
63f1a9
+					  N_("Add a network address."));
63f1a9
+      cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp,
63f1a9
+					 N_("[CARD]"),
63f1a9
+					 N_("perform a bootp autoconfiguration"));
63f1a9
+      cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6,
63f1a9
+					 N_("[CARD]"),
63f1a9
+					 N_("perform a bootp autoconfiguration"));
63f1a9
+      initialized = 1;
63f1a9
+    }
63f1a9
+}
63f1a9
+
63f1a9
+GRUB_MOD_FINI(efi_netfs)
63f1a9
+{
63f1a9
+  if (initialized)
63f1a9
+    {
63f1a9
+      grub_unregister_command (cmd_efi_lsroutes);
63f1a9
+      grub_unregister_command (cmd_efi_lscards);
63f1a9
+      grub_unregister_command (cmd_efi_lsaddrs);
63f1a9
+      grub_unregister_command (cmd_efi_addaddr);
63f1a9
+      grub_unregister_command (cmd_efi_bootp);
63f1a9
+      grub_unregister_command (cmd_efi_bootp6);
63f1a9
+      grub_efi_net_fs_fini ();
63f1a9
+      initialized = 0;
63f1a9
+      return;
63f1a9
+    }
63f1a9
+}
63f1a9
diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
63f1a9
new file mode 100644
63f1a9
index 00000000000..3f61fd2fa5b
63f1a9
--- /dev/null
63f1a9
+++ b/grub-core/net/efi/http.c
63f1a9
@@ -0,0 +1,419 @@
63f1a9
+
63f1a9
+#include <grub/efi/api.h>
63f1a9
+#include <grub/efi/efi.h>
63f1a9
+#include <grub/misc.h>
63f1a9
+#include <grub/net/efi.h>
63f1a9
+#include <grub/charset.h>
63f1a9
+
63f1a9
+static void
63f1a9
+http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
63f1a9
+{
63f1a9
+  grub_efi_http_config_data_t http_config;
63f1a9
+  grub_efi_httpv4_access_point_t httpv4_node;
63f1a9
+  grub_efi_httpv6_access_point_t httpv6_node;
63f1a9
+  grub_efi_status_t status;
63f1a9
+
63f1a9
+  grub_efi_http_t *http = dev->http;
63f1a9
+
63f1a9
+  grub_memset (&http_config, 0, sizeof(http_config));
63f1a9
+  http_config.http_version = GRUB_EFI_HTTPVERSION11;
63f1a9
+  http_config.timeout_millisec = 5000;
63f1a9
+
63f1a9
+  if (prefer_ip6)
63f1a9
+    {
63f1a9
+      grub_efi_uintn_t sz;
63f1a9
+      grub_efi_ip6_config_manual_address_t manual_address;
63f1a9
+
63f1a9
+      http_config.local_address_is_ipv6 = 1;
63f1a9
+      sz = sizeof (manual_address);
63f1a9
+      status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config,
63f1a9
+			GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
63f1a9
+			&sz, &manual_address);
63f1a9
+
63f1a9
+      if (status == GRUB_EFI_NOT_FOUND)
63f1a9
+	{
63f1a9
+	  grub_printf ("The MANUAL ADDRESS is not found\n");
63f1a9
+	}
63f1a9
+
63f1a9
+      /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_printf ("??? %d\n",(int) status);
63f1a9
+	  return;
63f1a9
+	}
63f1a9
+
63f1a9
+      grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address));
63f1a9
+      httpv6_node.local_port = 0;
63f1a9
+      http_config.access_point.ipv6_node = &httpv6_node;
63f1a9
+    }
63f1a9
+  else
63f1a9
+    {
63f1a9
+      http_config.local_address_is_ipv6 = 0;
63f1a9
+      grub_memset (&httpv4_node, 0, sizeof(httpv4_node));
63f1a9
+      httpv4_node.use_default_address = 1;
63f1a9
+
63f1a9
+      /* Use random port here */
63f1a9
+      /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */
63f1a9
+      httpv4_node.local_port = 0;
63f1a9
+      http_config.access_point.ipv4_node = &httpv4_node;
63f1a9
+    }
63f1a9
+
63f1a9
+  status = efi_call_2 (http->configure, http, &http_config);
63f1a9
+
63f1a9
+  if (status == GRUB_EFI_ALREADY_STARTED)
63f1a9
+    {
63f1a9
+      /* XXX: This hangs HTTPS boot */
63f1a9
+#if 0
63f1a9
+      if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  grub_error (GRUB_ERR_IO, N_("couldn't reset http instance"));
63f1a9
+	  grub_print_error ();
63f1a9
+	  return;
63f1a9
+	}
63f1a9
+      status = efi_call_2 (http->configure, http, &http_config);
63f1a9
+#endif
63f1a9
+      return;
63f1a9
+    }
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status);
63f1a9
+      grub_print_error ();
63f1a9
+      return ;
63f1a9
+    }
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_boolean_t request_callback_done;
63f1a9
+static grub_efi_boolean_t response_callback_done;
63f1a9
+
63f1a9
+static void
63f1a9
+grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)),
63f1a9
+				void *context __attribute__ ((unused)))
63f1a9
+{
63f1a9
+  request_callback_done = 1;
63f1a9
+}
63f1a9
+
63f1a9
+static void
63f1a9
+grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)),
63f1a9
+				void *context __attribute__ ((unused)))
63f1a9
+{
63f1a9
+  response_callback_done = 1;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_err_t
63f1a9
+efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size)
63f1a9
+{
63f1a9
+  grub_efi_http_request_data_t request_data;
63f1a9
+  grub_efi_http_message_t request_message;
63f1a9
+  grub_efi_http_token_t request_token;
63f1a9
+  grub_efi_http_response_data_t response_data;
63f1a9
+  grub_efi_http_message_t response_message;
63f1a9
+  grub_efi_http_token_t response_token;
63f1a9
+  grub_efi_http_header_t request_headers[3];
63f1a9
+
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
63f1a9
+  char *url = NULL;
63f1a9
+
63f1a9
+  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
63f1a9
+  request_headers[0].field_value = (grub_efi_char8_t *)server;
63f1a9
+  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
63f1a9
+  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
63f1a9
+  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
63f1a9
+  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
63f1a9
+
63f1a9
+  {
63f1a9
+    grub_efi_ipv6_address_t address;
63f1a9
+    const char *rest;
63f1a9
+    grub_efi_char16_t *ucs2_url;
63f1a9
+    grub_size_t url_len, ucs2_url_len;
63f1a9
+    const char *protocol = (use_https == 1) ? "https" : "http";
63f1a9
+
63f1a9
+    if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
63f1a9
+      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
63f1a9
+    else
63f1a9
+      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
63f1a9
+
63f1a9
+    if (!url)
63f1a9
+      {
63f1a9
+	return grub_errno;
63f1a9
+      }
63f1a9
+
63f1a9
+    url_len = grub_strlen (url);
63f1a9
+    ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8;
63f1a9
+    ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0]));
63f1a9
+
63f1a9
+    if (!ucs2_url)
63f1a9
+      {
63f1a9
+	grub_free (url);
63f1a9
+	return grub_errno;
63f1a9
+      }
63f1a9
+
63f1a9
+    ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */
63f1a9
+    ucs2_url[ucs2_url_len] = 0;
63f1a9
+    grub_free (url);
63f1a9
+    request_data.url = ucs2_url;
63f1a9
+  }
63f1a9
+
63f1a9
+  request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
63f1a9
+
63f1a9
+  request_message.data.request = &request_data;
63f1a9
+  request_message.header_count = 3;
63f1a9
+  request_message.headers = request_headers;
63f1a9
+  request_message.body_length = 0;
63f1a9
+  request_message.body = NULL;
63f1a9
+
63f1a9
+  /* request token */
63f1a9
+  request_token.event = NULL;
63f1a9
+  request_token.status = GRUB_EFI_NOT_READY;
63f1a9
+  request_token.message = &request_message;
63f1a9
+
63f1a9
+  request_callback_done = 0;
63f1a9
+  status = efi_call_5 (b->create_event,
63f1a9
+                       GRUB_EFI_EVT_NOTIFY_SIGNAL,
63f1a9
+                       GRUB_EFI_TPL_CALLBACK,
63f1a9
+                       grub_efi_http_request_callback,
63f1a9
+                       NULL,
63f1a9
+                       &request_token.event);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_free (request_data.url);
63f1a9
+      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
63f1a9
+    }
63f1a9
+
63f1a9
+  status = efi_call_2 (http->request, http, &request_token);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      efi_call_1 (b->close_event, request_token.event);
63f1a9
+      grub_free (request_data.url);
63f1a9
+      return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status);
63f1a9
+    }
63f1a9
+  /* TODO: Add Timeout */
63f1a9
+  while (!request_callback_done)
63f1a9
+    efi_call_1(http->poll, http);
63f1a9
+
63f1a9
+  response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS;
63f1a9
+  response_message.data.response = &response_data;
63f1a9
+  /* herader_count will be updated by the HTTP driver on response */
63f1a9
+  response_message.header_count = 0;
63f1a9
+  /* headers will be populated by the driver on response */
63f1a9
+  response_message.headers = NULL;
63f1a9
+  /* use zero BodyLength to only receive the response headers */
63f1a9
+  response_message.body_length = 0;
63f1a9
+  response_message.body = NULL;
63f1a9
+  response_token.event = NULL;
63f1a9
+
63f1a9
+  status = efi_call_5 (b->create_event,
63f1a9
+              GRUB_EFI_EVT_NOTIFY_SIGNAL,
63f1a9
+              GRUB_EFI_TPL_CALLBACK,
63f1a9
+              grub_efi_http_response_callback,
63f1a9
+              NULL,
63f1a9
+              &response_token.event);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      efi_call_1 (b->close_event, request_token.event);
63f1a9
+      grub_free (request_data.url);
63f1a9
+      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
63f1a9
+    }
63f1a9
+
63f1a9
+  response_token.status = GRUB_EFI_SUCCESS;
63f1a9
+  response_token.message = &response_message;
63f1a9
+
63f1a9
+  /* wait for HTTP response */
63f1a9
+  response_callback_done = 0;
63f1a9
+  status = efi_call_2 (http->response, http, &response_token);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      efi_call_1 (b->close_event, response_token.event);
63f1a9
+      efi_call_1 (b->close_event, request_token.event);
63f1a9
+      grub_free (request_data.url);
63f1a9
+      return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status);
63f1a9
+    }
63f1a9
+
63f1a9
+  /* TODO: Add Timeout */
63f1a9
+  while (!response_callback_done)
63f1a9
+    efi_call_1 (http->poll, http);
63f1a9
+
63f1a9
+  if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK)
63f1a9
+    {
63f1a9
+      grub_efi_http_status_code_t status_code = response_message.data.response->status_code;
63f1a9
+
63f1a9
+      if (response_message.headers)
63f1a9
+	efi_call_1 (b->free_pool, response_message.headers);
63f1a9
+      efi_call_1 (b->close_event, response_token.event);
63f1a9
+      efi_call_1 (b->close_event, request_token.event);
63f1a9
+      grub_free (request_data.url);
63f1a9
+      if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND)
63f1a9
+	{
63f1a9
+	  return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name);
63f1a9
+	}
63f1a9
+      else
63f1a9
+	{
63f1a9
+	  return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR,
63f1a9
+		  _("unsupported uefi http status code 0x%x"), status_code);
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  if (file_size)
63f1a9
+    {
63f1a9
+      int i;
63f1a9
+      /* parse the length of the file from the ContentLength header */
63f1a9
+      for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i)
63f1a9
+	{
63f1a9
+	  if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length"))
63f1a9
+	    {
63f1a9
+	      *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10);
63f1a9
+	      break;
63f1a9
+	    }
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  if (response_message.headers)
63f1a9
+    efi_call_1 (b->free_pool, response_message.headers);
63f1a9
+  efi_call_1 (b->close_event, response_token.event);
63f1a9
+  efi_call_1 (b->close_event, request_token.event);
63f1a9
+  grub_free (request_data.url);
63f1a9
+
63f1a9
+  return GRUB_ERR_NONE;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_ssize_t
63f1a9
+efihttp_read (struct grub_efi_net_device *dev,
63f1a9
+		  char *buf,
63f1a9
+		  grub_size_t len)
63f1a9
+{
63f1a9
+  grub_efi_http_message_t response_message;
63f1a9
+  grub_efi_http_token_t response_token;
63f1a9
+
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_size_t sum = 0;
63f1a9
+  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
63f1a9
+  grub_efi_http_t *http = dev->http;
63f1a9
+
63f1a9
+  if (!len)
63f1a9
+    {
63f1a9
+      grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read");
63f1a9
+      return -1;
63f1a9
+    }
63f1a9
+
63f1a9
+  efi_call_5 (b->create_event,
63f1a9
+              GRUB_EFI_EVT_NOTIFY_SIGNAL,
63f1a9
+              GRUB_EFI_TPL_CALLBACK,
63f1a9
+              grub_efi_http_response_callback,
63f1a9
+              NULL,
63f1a9
+              &response_token.event);
63f1a9
+
63f1a9
+  while (len)
63f1a9
+    {
63f1a9
+      response_message.data.response = NULL;
63f1a9
+      response_message.header_count = 0;
63f1a9
+      response_message.headers = NULL;
63f1a9
+      response_message.body_length = len;
63f1a9
+      response_message.body = buf;
63f1a9
+
63f1a9
+      response_token.message = &response_message;
63f1a9
+      response_token.status = GRUB_EFI_NOT_READY;
63f1a9
+
63f1a9
+      response_callback_done = 0;
63f1a9
+
63f1a9
+      status = efi_call_2 (http->response, http, &response_token);
63f1a9
+      if (status != GRUB_EFI_SUCCESS)
63f1a9
+	{
63f1a9
+	  efi_call_1 (b->close_event, response_token.event);
63f1a9
+	  grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status);
63f1a9
+	  return -1;
63f1a9
+	}
63f1a9
+
63f1a9
+      while (!response_callback_done)
63f1a9
+	efi_call_1(http->poll, http);
63f1a9
+
63f1a9
+      sum += response_message.body_length;
63f1a9
+      buf += response_message.body_length;
63f1a9
+      len -= response_message.body_length;
63f1a9
+    }
63f1a9
+
63f1a9
+  efi_call_1 (b->close_event, response_token.event);
63f1a9
+
63f1a9
+  return sum;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_err_t
63f1a9
+grub_efihttp_open (struct grub_efi_net_device *dev,
63f1a9
+		  int prefer_ip6 __attribute__ ((unused)),
63f1a9
+		  grub_file_t file,
63f1a9
+		  const char *filename __attribute__ ((unused)),
63f1a9
+		  int type)
63f1a9
+{
63f1a9
+  grub_err_t err;
63f1a9
+  grub_off_t size;
63f1a9
+  char *buf;
63f1a9
+
63f1a9
+  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
63f1a9
+  if (err != GRUB_ERR_NONE)
63f1a9
+    return err;
63f1a9
+
63f1a9
+  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
63f1a9
+  if (err != GRUB_ERR_NONE)
63f1a9
+    return err;
63f1a9
+
63f1a9
+  buf = grub_malloc (size);
63f1a9
+  efihttp_read (dev, buf, size);
63f1a9
+
63f1a9
+  file->size = size;
63f1a9
+  file->data = buf;
63f1a9
+  file->not_easily_seekable = 0;
63f1a9
+  file->device->net->offset = 0;
63f1a9
+
63f1a9
+  return GRUB_ERR_NONE;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_err_t
63f1a9
+grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)),
63f1a9
+		    int prefer_ip6 __attribute__ ((unused)),
63f1a9
+		    grub_file_t file)
63f1a9
+{
63f1a9
+  if (file->data)
63f1a9
+    grub_free (file->data);
63f1a9
+
63f1a9
+  file->data = 0;
63f1a9
+  file->offset = 0;
63f1a9
+  file->size = 0;
63f1a9
+  file->device->net->offset = 0;
63f1a9
+  return GRUB_ERR_NONE;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_ssize_t
63f1a9
+grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)),
63f1a9
+		  int prefer_ip6 __attribute__((unused)),
63f1a9
+		  grub_file_t file,
63f1a9
+		  char *buf,
63f1a9
+		  grub_size_t len)
63f1a9
+{
63f1a9
+  grub_size_t r = len;
63f1a9
+
63f1a9
+  if (!file->data || !buf || !len)
63f1a9
+    return 0;
63f1a9
+
63f1a9
+  if ((file->device->net->offset + len) > file->size)
63f1a9
+    r = file->size - file->device->net->offset;
63f1a9
+
63f1a9
+  if (r)
63f1a9
+    {
63f1a9
+      grub_memcpy (buf, (char *)file->data + file->device->net->offset, r);
63f1a9
+      file->device->net->offset += r;
63f1a9
+    }
63f1a9
+
63f1a9
+  return r;
63f1a9
+}
63f1a9
+
63f1a9
+struct grub_efi_net_io io_http =
63f1a9
+  {
63f1a9
+    .configure = http_configure,
63f1a9
+    .open = grub_efihttp_open,
63f1a9
+    .read = grub_efihttp_read,
63f1a9
+    .close = grub_efihttp_close
63f1a9
+  };
63f1a9
diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
63f1a9
new file mode 100644
63f1a9
index 00000000000..b711a5d9457
63f1a9
--- /dev/null
63f1a9
+++ b/grub-core/net/efi/ip4_config.c
63f1a9
@@ -0,0 +1,398 @@
63f1a9
+
63f1a9
+#include <grub/efi/api.h>
63f1a9
+#include <grub/efi/efi.h>
63f1a9
+#include <grub/misc.h>
63f1a9
+#include <grub/net/efi.h>
63f1a9
+#include <grub/charset.h>
63f1a9
+
63f1a9
+char *
63f1a9
+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
63f1a9
+{
63f1a9
+  char *hw_addr, *p;
63f1a9
+  int sz, s;
63f1a9
+  int i;
63f1a9
+
63f1a9
+  sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
63f1a9
+
63f1a9
+  hw_addr = grub_malloc (sz);
63f1a9
+  if (!hw_addr)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  p = hw_addr;
63f1a9
+  s = sz;
63f1a9
+  for (i = 0; i < (int)hw_address_size; i++)
63f1a9
+    {
63f1a9
+      grub_snprintf (p, sz, "%02x:", hw_address[i]);
63f1a9
+      p +=  sizeof ("XX:") - 1;
63f1a9
+      s -=  sizeof ("XX:") - 1;
63f1a9
+    }
63f1a9
+
63f1a9
+  hw_addr[sz - 2] = '\0';
63f1a9
+  return hw_addr;
63f1a9
+}
63f1a9
+
63f1a9
+char *
63f1a9
+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address)
63f1a9
+{
63f1a9
+  char *addr;
63f1a9
+
63f1a9
+  addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
63f1a9
+  if (!addr)
63f1a9
+      return NULL;
63f1a9
+
63f1a9
+  /* FIXME: Use grub_xasprintf ? */
63f1a9
+  grub_snprintf (addr,
63f1a9
+	  sizeof ("XXX.XXX.XXX.XXX"),
63f1a9
+	  "%u.%u.%u.%u",
63f1a9
+	  (*address)[0],
63f1a9
+	  (*address)[1],
63f1a9
+	  (*address)[2],
63f1a9
+	  (*address)[3]);
63f1a9
+
63f1a9
+  return addr;
63f1a9
+}
63f1a9
+
63f1a9
+int
63f1a9
+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
63f1a9
+{
63f1a9
+  grub_uint32_t newip = 0;
63f1a9
+  int i;
63f1a9
+  const char *ptr = val;
63f1a9
+
63f1a9
+  for (i = 0; i < 4; i++)
63f1a9
+    {
63f1a9
+      unsigned long t;
63f1a9
+      t = grub_strtoul (ptr, (char **) &ptr, 0);
63f1a9
+      if (grub_errno)
63f1a9
+	{
63f1a9
+	  grub_errno = GRUB_ERR_NONE;
63f1a9
+	  return 0;
63f1a9
+	}
63f1a9
+      if (*ptr != '.' && i == 0)
63f1a9
+	{
63f1a9
+	  /* XXX: t is in host byte order */
63f1a9
+	  newip = t;
63f1a9
+	  break;
63f1a9
+	}
63f1a9
+      if (t & ~0xff)
63f1a9
+	return 0;
63f1a9
+      newip <<= 8;
63f1a9
+      newip |= t;
63f1a9
+      if (i != 3 && *ptr != '.')
63f1a9
+	return 0;
63f1a9
+      ptr++;
63f1a9
+    }
63f1a9
+
63f1a9
+  newip =  grub_cpu_to_be32 (newip);
63f1a9
+
63f1a9
+  grub_memcpy (address, &newip, sizeof(*address));
63f1a9
+
63f1a9
+  if (rest)
63f1a9
+    *rest = (ptr - 1);
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_ip4_config2_interface_info_t *
63f1a9
+efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config)
63f1a9
+{
63f1a9
+  grub_efi_uintn_t sz;
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_ip4_config2_interface_info_t *interface_info;
63f1a9
+
63f1a9
+  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
63f1a9
+  interface_info = grub_malloc (sz);
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  status = efi_call_4 (ip4_config->get_data, ip4_config,
63f1a9
+		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
63f1a9
+		&sz, interface_info);
63f1a9
+
63f1a9
+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
63f1a9
+    {
63f1a9
+      grub_free (interface_info);
63f1a9
+      interface_info = grub_malloc (sz);
63f1a9
+      status = efi_call_4 (ip4_config->get_data, ip4_config,
63f1a9
+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
63f1a9
+		    &sz, interface_info);
63f1a9
+    }
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_free (interface_info);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  return interface_info;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_ip4_config2_manual_address_t *
63f1a9
+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
63f1a9
+{
63f1a9
+  grub_efi_uintn_t sz;
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_ip4_config2_manual_address_t *manual_address;
63f1a9
+
63f1a9
+  sz = sizeof (*manual_address);
63f1a9
+  manual_address = grub_malloc (sz);
63f1a9
+  if (!manual_address)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  status = efi_call_4 (ip4_config->get_data, ip4_config,
63f1a9
+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
63f1a9
+		    &sz, manual_address);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_free (manual_address);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  return manual_address;
63f1a9
+}
63f1a9
+
63f1a9
+char *
63f1a9
+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip4_config2_interface_info_t *interface_info;
63f1a9
+  char *name;
63f1a9
+
63f1a9
+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
63f1a9
+
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
63f1a9
+		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
63f1a9
+  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
63f1a9
+		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
63f1a9
+  grub_free (interface_info);
63f1a9
+  return name;
63f1a9
+}
63f1a9
+
63f1a9
+static char *
63f1a9
+grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip4_config2_interface_info_t *interface_info;
63f1a9
+  char *hw_addr;
63f1a9
+
63f1a9
+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
63f1a9
+
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
63f1a9
+  grub_free (interface_info);
63f1a9
+
63f1a9
+  return hw_addr;
63f1a9
+}
63f1a9
+
63f1a9
+static char *
63f1a9
+grub_efi_ip4_interface_address (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip4_config2_manual_address_t *manual_address;
63f1a9
+  char *addr;
63f1a9
+
63f1a9
+  manual_address = efi_ip4_config_manual_address (dev->ip4_config);
63f1a9
+
63f1a9
+  if (!manual_address)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  addr = grub_efi_ip4_address_to_string (&manual_address->address);
63f1a9
+  grub_free (manual_address);
63f1a9
+  return addr;
63f1a9
+}
63f1a9
+
63f1a9
+
63f1a9
+static int
63f1a9
+address_mask_size (grub_efi_ipv4_address_t *address)
63f1a9
+{
63f1a9
+  grub_uint8_t i;
63f1a9
+  grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address));
63f1a9
+
63f1a9
+  if (u32_addr == 0)
63f1a9
+    return 0;
63f1a9
+
63f1a9
+  for (i = 0; i < 32 ; ++i)
63f1a9
+    {
63f1a9
+      if (u32_addr == ((0xffffffff >> i) << i))
63f1a9
+	return (32 - i);
63f1a9
+    }
63f1a9
+
63f1a9
+  return -1;
63f1a9
+}
63f1a9
+
63f1a9
+static char **
63f1a9
+grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip4_config2_interface_info_t *interface_info;
63f1a9
+  char **ret;
63f1a9
+  int i, id;
63f1a9
+
63f1a9
+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
63f1a9
+
63f1a9
+  if (!ret)
63f1a9
+    {
63f1a9
+      grub_free (interface_info);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  id = 0;
63f1a9
+  for (i = 0; i < (int)interface_info->route_table_size; i++)
63f1a9
+    {
63f1a9
+      char *subnet, *gateway, *mask;
63f1a9
+      grub_uint32_t u32_subnet, u32_gateway;
63f1a9
+      int mask_size;
63f1a9
+      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
63f1a9
+      grub_efi_net_interface_t *inf;
63f1a9
+      char *interface_name = NULL;
63f1a9
+
63f1a9
+      for (inf = dev->net_interfaces; inf; inf = inf->next)
63f1a9
+	if (!inf->prefer_ip6)
63f1a9
+	  interface_name = inf->name;
63f1a9
+
63f1a9
+      u32_gateway = grub_get_unaligned32 (&route_table->gateway_address);
63f1a9
+      gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address);
63f1a9
+      u32_subnet = grub_get_unaligned32 (&route_table->subnet_address);
63f1a9
+      subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address);
63f1a9
+      mask_size = address_mask_size (&route_table->subnet_mask);
63f1a9
+      mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask);
63f1a9
+      if (u32_subnet && !u32_gateway && interface_name)
63f1a9
+	ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name);
63f1a9
+      else if (u32_subnet && u32_gateway)
63f1a9
+	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
63f1a9
+      else if (!u32_subnet && u32_gateway)
63f1a9
+	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
63f1a9
+      grub_free (subnet);
63f1a9
+      grub_free (gateway);
63f1a9
+      grub_free (mask);
63f1a9
+    }
63f1a9
+
63f1a9
+  ret[id] = NULL;
63f1a9
+  grub_free (interface_info);
63f1a9
+  return ret;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_net_interface_t *
63f1a9
+grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
63f1a9
+{
63f1a9
+  grub_efi_ip4_config2_interface_info_t *interface_info;
63f1a9
+  grub_efi_net_interface_t *inf;
63f1a9
+  int i;
63f1a9
+  grub_efi_ipv4_address_t *address = &ip_address->ip4;
63f1a9
+
63f1a9
+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  for (i = 0; i < (int)interface_info->route_table_size; i++)
63f1a9
+    {
63f1a9
+      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
63f1a9
+      grub_uint32_t u32_address, u32_mask, u32_subnet;
63f1a9
+
63f1a9
+      u32_address = grub_get_unaligned32 (address);
63f1a9
+      u32_subnet = grub_get_unaligned32 (route_table->subnet_address);
63f1a9
+      u32_mask = grub_get_unaligned32 (route_table->subnet_mask);
63f1a9
+
63f1a9
+      /* SKIP Default GATEWAY */
63f1a9
+      if (!u32_subnet && !u32_mask)
63f1a9
+	continue;
63f1a9
+
63f1a9
+      if ((u32_address & u32_mask) == u32_subnet)
63f1a9
+	{
63f1a9
+	  for (inf = dev->net_interfaces; inf; inf = inf->next)
63f1a9
+	    if (!inf->prefer_ip6)
63f1a9
+	      {
63f1a9
+		grub_free (interface_info);
63f1a9
+		return inf;
63f1a9
+	      }
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  grub_free (interface_info);
63f1a9
+  return NULL;
63f1a9
+}
63f1a9
+
63f1a9
+static int
63f1a9
+grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev,
63f1a9
+	    grub_efi_net_ip_manual_address_t *net_ip,
63f1a9
+	    int with_subnet)
63f1a9
+{
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4;
63f1a9
+
63f1a9
+  if (!with_subnet)
63f1a9
+    {
63f1a9
+      grub_efi_ip4_config2_manual_address_t *manual_address =
63f1a9
+      efi_ip4_config_manual_address (dev->ip4_config);
63f1a9
+
63f1a9
+      if (manual_address)
63f1a9
+	{
63f1a9
+	  grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask));
63f1a9
+	  grub_free (manual_address);
63f1a9
+	}
63f1a9
+      else
63f1a9
+	{
63f1a9
+	  /* XXX: */
63f1a9
+	  address->subnet_mask[0] = 0xff;
63f1a9
+	  address->subnet_mask[1] = 0xff;
63f1a9
+	  address->subnet_mask[2] = 0xff;
63f1a9
+	  address->subnet_mask[3] = 0;
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
63f1a9
+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
63f1a9
+		    sizeof(*address), address);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+static int
63f1a9
+grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev,
63f1a9
+	      grub_efi_net_ip_address_t *address)
63f1a9
+{
63f1a9
+  grub_efi_status_t status;
63f1a9
+
63f1a9
+  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
63f1a9
+		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
63f1a9
+		sizeof (address->ip4), &address->ip4);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+/* FIXME: Multiple DNS */
63f1a9
+static int
63f1a9
+grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev,
63f1a9
+	      grub_efi_net_ip_address_t *address)
63f1a9
+{
63f1a9
+  grub_efi_status_t status;
63f1a9
+
63f1a9
+  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
63f1a9
+		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
63f1a9
+		sizeof (address->ip4), &address->ip4);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t)
63f1a9
+  {
63f1a9
+    .get_hw_address = grub_efi_ip4_interface_hw_address,
63f1a9
+    .get_address = grub_efi_ip4_interface_address,
63f1a9
+    .get_route_table = grub_efi_ip4_interface_route_table,
63f1a9
+    .best_interface = grub_efi_ip4_interface_match,
63f1a9
+    .set_address = grub_efi_ip4_interface_set_manual_address,
63f1a9
+    .set_gateway = grub_efi_ip4_interface_set_gateway,
63f1a9
+    .set_dns = grub_efi_ip4_interface_set_dns
63f1a9
+  };
63f1a9
diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
63f1a9
new file mode 100644
63f1a9
index 00000000000..c0d920fa44c
63f1a9
--- /dev/null
63f1a9
+++ b/grub-core/net/efi/ip6_config.c
63f1a9
@@ -0,0 +1,422 @@
63f1a9
+#include <grub/efi/api.h>
63f1a9
+#include <grub/efi/efi.h>
63f1a9
+#include <grub/misc.h>
63f1a9
+#include <grub/net/efi.h>
63f1a9
+#include <grub/charset.h>
63f1a9
+
63f1a9
+char *
63f1a9
+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
63f1a9
+{
63f1a9
+  char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"));
63f1a9
+  char *p;
63f1a9
+  int i;
63f1a9
+  int squash;
63f1a9
+
63f1a9
+  if (!str)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  p = str;
63f1a9
+  squash = 0;
63f1a9
+  for (i = 0; i < 8; ++i)
63f1a9
+    {
63f1a9
+      grub_uint16_t addr;
63f1a9
+
63f1a9
+      if (i == 7)
63f1a9
+	squash = 2;
63f1a9
+
63f1a9
+      addr = grub_get_unaligned16 (address + i * 2);
63f1a9
+
63f1a9
+      if (grub_be_to_cpu16 (addr))
63f1a9
+	{
63f1a9
+	  char buf[sizeof ("XXXX")];
63f1a9
+	  if (i > 0)
63f1a9
+	    *p++ = ':';
63f1a9
+	  grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr));
63f1a9
+	  grub_strcpy (p, buf);
63f1a9
+	  p += grub_strlen (buf);
63f1a9
+
63f1a9
+	  if (squash == 1)
63f1a9
+	    squash = 2;
63f1a9
+	}
63f1a9
+      else
63f1a9
+	{
63f1a9
+	  if (squash == 0)
63f1a9
+	    {
63f1a9
+	      *p++ = ':';
63f1a9
+	      squash = 1;
63f1a9
+	    }
63f1a9
+	  else if (squash == 2)
63f1a9
+	    {
63f1a9
+	      *p++ = ':';
63f1a9
+	      *p++ = '0';
63f1a9
+	    }
63f1a9
+	}
63f1a9
+    }
63f1a9
+  *p = '\0';
63f1a9
+  return str;
63f1a9
+}
63f1a9
+
63f1a9
+int
63f1a9
+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest)
63f1a9
+{
63f1a9
+  grub_uint16_t newip[8];
63f1a9
+  const char *ptr = val;
63f1a9
+  int word, quaddot = -1;
63f1a9
+  int bracketed = 0;
63f1a9
+
63f1a9
+  if (ptr[0] == '[') {
63f1a9
+    bracketed = 1;
63f1a9
+    ptr++;
63f1a9
+  }
63f1a9
+
63f1a9
+  if (ptr[0] == ':' && ptr[1] != ':')
63f1a9
+    return 0;
63f1a9
+  if (ptr[0] == ':')
63f1a9
+    ptr++;
63f1a9
+
63f1a9
+  for (word = 0; word < 8; word++)
63f1a9
+    {
63f1a9
+      unsigned long t;
63f1a9
+      if (*ptr == ':')
63f1a9
+	{
63f1a9
+	  quaddot = word;
63f1a9
+	  word--;
63f1a9
+	  ptr++;
63f1a9
+	  continue;
63f1a9
+	}
63f1a9
+      t = grub_strtoul (ptr, (char **) &ptr, 16);
63f1a9
+      if (grub_errno)
63f1a9
+	{
63f1a9
+	  grub_errno = GRUB_ERR_NONE;
63f1a9
+	  break;
63f1a9
+	}
63f1a9
+      if (t & ~0xffff)
63f1a9
+	return 0;
63f1a9
+      newip[word] = grub_cpu_to_be16 (t);
63f1a9
+      if (*ptr != ':')
63f1a9
+	break;
63f1a9
+      ptr++;
63f1a9
+    }
63f1a9
+  if (quaddot == -1 && word < 7)
63f1a9
+    return 0;
63f1a9
+  if (quaddot != -1)
63f1a9
+    {
63f1a9
+      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
63f1a9
+		    (word - quaddot + 1) * sizeof (newip[0]));
63f1a9
+      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
63f1a9
+    }
63f1a9
+  grub_memcpy (address, newip, 16);
63f1a9
+  if (bracketed && *ptr == ']') {
63f1a9
+    ptr++;
63f1a9
+  }
63f1a9
+  if (rest)
63f1a9
+    *rest = ptr;
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_ip6_config_interface_info_t *
63f1a9
+efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config)
63f1a9
+{
63f1a9
+  grub_efi_uintn_t sz;
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_ip6_config_interface_info_t *interface_info;
63f1a9
+
63f1a9
+  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
63f1a9
+  interface_info = grub_malloc (sz);
63f1a9
+
63f1a9
+  status = efi_call_4 (ip6_config->get_data, ip6_config,
63f1a9
+		GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
63f1a9
+		&sz, interface_info);
63f1a9
+
63f1a9
+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
63f1a9
+    {
63f1a9
+      grub_free (interface_info);
63f1a9
+      interface_info = grub_malloc (sz);
63f1a9
+      status = efi_call_4 (ip6_config->get_data, ip6_config,
63f1a9
+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
63f1a9
+		    &sz, interface_info);
63f1a9
+    }
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_free (interface_info);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  return interface_info;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_ip6_config_manual_address_t *
63f1a9
+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
63f1a9
+{
63f1a9
+  grub_efi_uintn_t sz;
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_ip6_config_manual_address_t *manual_address;
63f1a9
+
63f1a9
+  sz = sizeof (*manual_address);
63f1a9
+  manual_address = grub_malloc (sz);
63f1a9
+  if (!manual_address)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  status = efi_call_4 (ip6_config->get_data, ip6_config,
63f1a9
+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
63f1a9
+		    &sz, manual_address);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    {
63f1a9
+      grub_free (manual_address);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  return manual_address;
63f1a9
+}
63f1a9
+
63f1a9
+char *
63f1a9
+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip6_config_interface_info_t *interface_info;
63f1a9
+  char *name;
63f1a9
+
63f1a9
+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
63f1a9
+
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
63f1a9
+		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
63f1a9
+  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
63f1a9
+		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
63f1a9
+  grub_free (interface_info);
63f1a9
+  return name;
63f1a9
+}
63f1a9
+
63f1a9
+static char *
63f1a9
+grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip6_config_interface_info_t *interface_info;
63f1a9
+  char *hw_addr;
63f1a9
+
63f1a9
+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
63f1a9
+
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
63f1a9
+  grub_free (interface_info);
63f1a9
+
63f1a9
+  return hw_addr;
63f1a9
+}
63f1a9
+
63f1a9
+static char *
63f1a9
+grub_efi_ip6_interface_address (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip6_config_manual_address_t *manual_address;
63f1a9
+  char *addr;
63f1a9
+
63f1a9
+  manual_address = efi_ip6_config_manual_address (dev->ip6_config);
63f1a9
+
63f1a9
+  if (!manual_address)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address);
63f1a9
+  grub_free (manual_address);
63f1a9
+  return addr;
63f1a9
+}
63f1a9
+
63f1a9
+static char **
63f1a9
+grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
63f1a9
+{
63f1a9
+  grub_efi_ip6_config_interface_info_t *interface_info;
63f1a9
+  char **ret;
63f1a9
+  int i, id;
63f1a9
+
63f1a9
+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
63f1a9
+
63f1a9
+  if (!ret)
63f1a9
+    {
63f1a9
+      grub_free (interface_info);
63f1a9
+      return NULL;
63f1a9
+    }
63f1a9
+
63f1a9
+  id = 0;
63f1a9
+  for (i = 0; i < (int)interface_info->route_count ; i++)
63f1a9
+    {
63f1a9
+      char *gateway, *destination;
63f1a9
+      grub_uint64_t u64_gateway[2];
63f1a9
+      grub_uint64_t u64_destination[2];
63f1a9
+      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
63f1a9
+      grub_efi_net_interface_t *inf;
63f1a9
+      char *interface_name = NULL;
63f1a9
+
63f1a9
+      gateway = grub_efi_ip6_address_to_string (&route_table->gateway);
63f1a9
+      destination = grub_efi_ip6_address_to_string (&route_table->destination);
63f1a9
+
63f1a9
+      u64_gateway[0] = grub_get_unaligned64 (route_table->gateway);
63f1a9
+      u64_gateway[1] = grub_get_unaligned64 (route_table->gateway + 8);
63f1a9
+      u64_destination[0] = grub_get_unaligned64 (route_table->destination);
63f1a9
+      u64_destination[1] = grub_get_unaligned64 (route_table->destination + 8);
63f1a9
+
63f1a9
+      for (inf = dev->net_interfaces; inf; inf = inf->next)
63f1a9
+	if (inf->prefer_ip6)
63f1a9
+	  interface_name = inf->name;
63f1a9
+
63f1a9
+      if ((!u64_gateway[0] && !u64_gateway[1])
63f1a9
+	  && (u64_destination[0] || u64_destination[1]))
63f1a9
+	{
63f1a9
+	  if (interface_name)
63f1a9
+	    {
63f1a9
+	      if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL)
63f1a9
+	      && (!u64_destination[1])
63f1a9
+	      && (route_table->prefix_length == 64))
63f1a9
+		ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
63f1a9
+	      else
63f1a9
+		ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
63f1a9
+	    }
63f1a9
+	}
63f1a9
+      else if ((u64_gateway[0] || u64_gateway[1])
63f1a9
+	  && (u64_destination[0] || u64_destination[1]))
63f1a9
+	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
63f1a9
+      else if ((u64_gateway[0] || u64_gateway[1])
63f1a9
+	  && (!u64_destination[0] && !u64_destination[1]))
63f1a9
+	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
63f1a9
+
63f1a9
+      grub_free (gateway);
63f1a9
+      grub_free (destination);
63f1a9
+    }
63f1a9
+
63f1a9
+  ret[id] = NULL;
63f1a9
+  grub_free (interface_info);
63f1a9
+  return ret;
63f1a9
+}
63f1a9
+
63f1a9
+static grub_efi_net_interface_t *
63f1a9
+grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
63f1a9
+{
63f1a9
+  grub_efi_ip6_config_interface_info_t *interface_info;
63f1a9
+  grub_efi_net_interface_t *inf;
63f1a9
+  int i;
63f1a9
+  grub_efi_ipv6_address_t *address = &ip_address->ip6;
63f1a9
+
63f1a9
+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
63f1a9
+  if (!interface_info)
63f1a9
+    return NULL;
63f1a9
+
63f1a9
+  for (i = 0; i < (int)interface_info->route_count ; i++)
63f1a9
+    {
63f1a9
+      grub_uint64_t u64_addr[2];
63f1a9
+      grub_uint64_t u64_subnet[2];
63f1a9
+      grub_uint64_t u64_mask[2];
63f1a9
+
63f1a9
+      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
63f1a9
+
63f1a9
+      /* SKIP Default GATEWAY */
63f1a9
+      if (route_table->prefix_length == 0)
63f1a9
+	continue;
63f1a9
+
63f1a9
+      u64_addr[0] = grub_get_unaligned64 (address);
63f1a9
+      u64_addr[1] = grub_get_unaligned64 (address + 4);
63f1a9
+      u64_subnet[0] = grub_get_unaligned64 (route_table->destination);
63f1a9
+      u64_subnet[1] = grub_get_unaligned64 (route_table->destination + 8);
63f1a9
+      u64_mask[0] = (route_table->prefix_length <= 64) ?
63f1a9
+	    0xffffffffffffffffULL << (64 - route_table->prefix_length) :
63f1a9
+	    0xffffffffffffffffULL;
63f1a9
+      u64_mask[1] = (route_table->prefix_length <= 64) ?
63f1a9
+	    0 :
63f1a9
+	    0xffffffffffffffffULL << (128 - route_table->prefix_length);
63f1a9
+
63f1a9
+      if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0])
63f1a9
+	  && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1]))
63f1a9
+	{
63f1a9
+	  for (inf = dev->net_interfaces; inf; inf = inf->next)
63f1a9
+	    if (inf->prefer_ip6)
63f1a9
+	      {
63f1a9
+		grub_free (interface_info);
63f1a9
+		return inf;
63f1a9
+	      }
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  grub_free (interface_info);
63f1a9
+  return NULL;
63f1a9
+}
63f1a9
+
63f1a9
+static int
63f1a9
+grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev,
63f1a9
+	    grub_efi_net_ip_manual_address_t *net_ip,
63f1a9
+	    int with_subnet)
63f1a9
+{
63f1a9
+  grub_efi_status_t status;
63f1a9
+  grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6;
63f1a9
+
63f1a9
+  if (!with_subnet)
63f1a9
+    {
63f1a9
+      grub_efi_ip6_config_manual_address_t *manual_address =
63f1a9
+      efi_ip6_config_manual_address (dev->ip6_config);
63f1a9
+
63f1a9
+      if (manual_address)
63f1a9
+	{
63f1a9
+	  address->prefix_length = manual_address->prefix_length;
63f1a9
+	  grub_free (manual_address);
63f1a9
+	}
63f1a9
+      else
63f1a9
+	{
63f1a9
+	  /* XXX: */
63f1a9
+	  address->prefix_length = 64;
63f1a9
+	}
63f1a9
+    }
63f1a9
+
63f1a9
+  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
63f1a9
+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
63f1a9
+		    sizeof(*address), address);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+static int
63f1a9
+grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev,
63f1a9
+	      grub_efi_net_ip_address_t *address)
63f1a9
+{
63f1a9
+  grub_efi_status_t status;
63f1a9
+
63f1a9
+  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
63f1a9
+		GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
63f1a9
+		sizeof (address->ip6), &address->ip6);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+static int
63f1a9
+grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev,
63f1a9
+	      grub_efi_net_ip_address_t *address)
63f1a9
+{
63f1a9
+
63f1a9
+  grub_efi_status_t status;
63f1a9
+
63f1a9
+  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
63f1a9
+		GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
63f1a9
+		sizeof (address->ip6), &address->ip6);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+  return 1;
63f1a9
+}
63f1a9
+
63f1a9
+grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t)
63f1a9
+  {
63f1a9
+    .get_hw_address = grub_efi_ip6_interface_hw_address,
63f1a9
+    .get_address = grub_efi_ip6_interface_address,
63f1a9
+    .get_route_table = grub_efi_ip6_interface_route_table,
63f1a9
+    .best_interface = grub_efi_ip6_interface_match,
63f1a9
+    .set_address = grub_efi_ip6_interface_set_manual_address,
63f1a9
+    .set_gateway = grub_efi_ip6_interface_set_gateway,
63f1a9
+    .set_dns = grub_efi_ip6_interface_set_dns
63f1a9
+  };
63f1a9
diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
63f1a9
new file mode 100644
63f1a9
index 00000000000..9e0078ac1c6
63f1a9
--- /dev/null
63f1a9
+++ b/grub-core/net/efi/net.c
63f1a9
@@ -0,0 +1,1428 @@
63f1a9
+#include <grub/net.h>
63f1a9
+#include <grub/env.h>
63f1a9
+#include <grub/mm.h>
63f1a9
+#include <grub/misc.h>
63f1a9
+#include <grub/dl.h>
63f1a9
+#include <grub/command.h>
63f1a9
+#include <grub/efi/api.h>
63f1a9
+#include <grub/efi/efi.h>
63f1a9
+#include <grub/i18n.h>
63f1a9
+#include <grub/bufio.h>
63f1a9
+#include <grub/efi/http.h>
63f1a9
+#include <grub/efi/dhcp.h>
63f1a9
+#include <grub/net/efi.h>
63f1a9
+#include <grub/charset.h>
63f1a9
+
63f1a9
+GRUB_MOD_LICENSE ("GPLv3+");
63f1a9
+
63f1a9
+#define GRUB_EFI_IP6_PREFIX_LENGTH 64
63f1a9
+
63f1a9
+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
63f1a9
+static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
63f1a9
+static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID;
63f1a9
+
63f1a9
+struct grub_efi_net_device *net_devices;
63f1a9
+
63f1a9
+static char *default_server;
63f1a9
+static grub_efi_net_interface_t *net_interface;
63f1a9
+static grub_efi_net_interface_t *net_default_interface;
63f1a9
+
63f1a9
+#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6)
63f1a9
+#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type)
63f1a9
+#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz)
63f1a9
+#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file)
63f1a9
+#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__)
63f1a9
+
63f1a9
+static grub_efi_handle_t
63f1a9
+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
63f1a9
+                            grub_efi_device_path_t **r_device_path)
63f1a9
+{
63f1a9
+  grub_efi_handle_t handle;
63f1a9
+  grub_efi_status_t status;
63f1a9
+
63f1a9
+  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
63f1a9
+                      protocol, &device_path, &handle);
63f1a9
+
63f1a9
+  if (status != GRUB_EFI_SUCCESS)
63f1a9
+    return 0;
63f1a9
+
63f1a9
+  if (r_device_path)
63f1a9
+    *r_device_path = device_path;
63f1a9
+
63f1a9
+  return handle;
63f1a9
+}
63f1a9
+
63f1a9
+static int