File grub2-efinet-httpboot.patch of Package grub2.4793

Index: grub-2.02~beta2/grub-core/net/bootp.c
===================================================================
--- grub-2.02~beta2.orig/grub-core/net/bootp.c
+++ grub-2.02~beta2/grub-core/net/bootp.c
@@ -121,6 +121,11 @@ parse_dhcp_vendor (const char *name, con
                                      taglength);
           break;
 
+        case GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER:
+          grub_env_set_net_property (name, "vendor_class_identifier", (const char *) ptr,
+                                     taglength);
+	  break;
+
 	  /* If you need any other options please contact GRUB
 	     development team.  */
 	}
@@ -180,9 +185,83 @@ grub_net_configure_by_dhcp_ack (const ch
       grub_net_add_route (name, target, inter);
     }
 
+  if (size > OFFSET_OF (vendor, bp))
+    parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
+  grub_net_add_ipv4_local (inter, mask);
+
   if (size > OFFSET_OF (boot_file, bp))
-    grub_env_set_net_property (name, "boot_file", bp->boot_file,
+    {
+      char *cidvar;
+      const char *cid;
+      cidvar = grub_xasprintf ("net_%s_%s", name, "vendor_class_identifier");
+      cid = grub_env_get (cidvar);
+      grub_free (cidvar);
+
+      if (cid && grub_strcmp (cid, "HTTPClient") == 0)
+	{
+	  char *p, *q, *proto, *ip, *pa;
+	  grub_size_t len;
+	  p = grub_strstr (bp->boot_file, "://");
+	  q = NULL;
+	  if (p)
+             q = grub_strchr (p + grub_strlen("://"), '/');
+
+	  if (p && q)
+	    {
+	      len = p - bp->boot_file;
+	      proto = grub_malloc (len + 1);
+	      grub_memcpy (proto, bp->boot_file, len);
+	      proto[len] = '\0';
+	      len = q - (p + 3);
+	      ip = grub_malloc (len + 1);
+	      grub_memcpy (ip, p + 3, len);
+	      ip[len] = '\0';
+	      pa = grub_strdup (q);
+	      grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa));
+	      if (is_def)
+		{
+		  grub_net_default_server = grub_strdup (ip);
+		  grub_env_set ("net_default_interface", name);
+		  grub_env_export ("net_default_interface");
+		}
+	      if (device && !*device)
+		{
+		  *device = grub_xasprintf ("%s,%s", proto, ip);
+		  grub_print_error ();
+		}
+	      if (path)
+		{
+		  *path = grub_strdup (pa);
+		  grub_print_error ();
+      		  if (*path)
+		    {
+		      char *slash;
+		      slash = grub_strrchr (*path, '/');
+		      if (slash)
+			*slash = 0;
+		      else
+			**path = 0;
+		    }
+		}
+	      inter->dhcp_ack = grub_malloc (size);
+	      if (inter->dhcp_ack)
+		{
+		  grub_memcpy (inter->dhcp_ack, bp, size);
+		  inter->dhcp_acklen = size;
+		}
+	      else
+		grub_errno = GRUB_ERR_NONE;
+
+	      grub_free (proto);
+	      grub_free (ip);
+	      grub_free (pa);
+	      return inter;
+	    }
+	}
+      else
+	grub_env_set_net_property (name, "boot_file", bp->boot_file,
                                sizeof (bp->boot_file));
+    }
   if (is_def)
     grub_net_default_server = 0;
   if (is_def && !grub_net_default_server && bp->server_ip)
@@ -241,9 +320,6 @@ grub_net_configure_by_dhcp_ack (const ch
 	    **path = 0;
 	}
     }
-  if (size > OFFSET_OF (vendor, bp))
-    parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
-  grub_net_add_ipv4_local (inter, mask);
   
   inter->dhcp_ack = grub_malloc (size);
   if (inter->dhcp_ack)
@@ -257,54 +333,6 @@ grub_net_configure_by_dhcp_ack (const ch
   return inter;
 }
 
-struct grub_dhcpv6_option {
-  grub_uint16_t code;
-  grub_uint16_t len;
-  grub_uint8_t data[0];
-} GRUB_PACKED;
-
-
-struct grub_dhcpv6_iana_option {
-  grub_uint32_t iaid;
-  grub_uint32_t t1;
-  grub_uint32_t t2;
-  grub_uint8_t data[0];
-} GRUB_PACKED;
-
-struct grub_dhcpv6_iaaddr_option {
-  grub_uint8_t addr[16];
-  grub_uint32_t preferred_lifetime;
-  grub_uint32_t valid_lifetime;
-  grub_uint8_t data[0];
-} GRUB_PACKED;
-
-struct grub_DUID_LL
-{
-  grub_uint16_t type;
-  grub_uint16_t hw_type;
-  grub_uint8_t hwaddr[6];
-} GRUB_PACKED;
-
-struct grub_dhcpv6_dns_servers {
-  grub_uint8_t addr[16];
-  grub_uint8_t next_addr[0];
-} GRUB_PACKED;
-
-//http://tools.ietf.org/html/rfc1035#section-3.1
-
-#define DHCPv6_REPLY 7
-#define DHCPv6_ADVERTISE 2
-#define DHCPv6_REQUEST 3
-#define OPTION_BOOTFILE_URL 59
-//RFC3646 http://tools.ietf.org/html/rfc3646
-#define OPTION_DNS_SERVERS 23
-#define OPTION_IA_NA 3
-#define OPTION_IAADDR 5
-#define OPTION_CLIENTID 1
-#define OPTION_SERVERID 2
-#define OPTION_ORO 6
-#define OPTION_ELAPSED_TIME 8
-
 struct grub_dhcpv6_session
 {
   struct grub_dhcpv6_session *next;
@@ -554,19 +582,15 @@ find_bootfile_url (const struct grub_net
 
   ip_start = ip_end = NULL;
   ip_start = bootfile_url + grub_strlen(pr);
+  path = grub_strchr (ip_start, '/');
 
-  if (*ip_start != '[')
-    ip_start = NULL;
-  else
-    ip_end = grub_strchr (++ip_start, ']');
-
-  if (!ip_start || !ip_end)
+  if (!ip_start || !path)
     {
-      grub_error (GRUB_ERR_IO, N_("IPv6-address not in square brackets"));
+      grub_error (GRUB_ERR_IO, N_("invalid url format"));
       goto cleanup;
     }
 
-  ip_len = ip_end - ip_start;
+  ip_len = path - ip_start;
 
   if (proto)
     {
@@ -582,6 +606,13 @@ find_bootfile_url (const struct grub_net
 
   if (server_ip)
     {
+
+      if (ip_len > 2 && *ip_start == '[' && *(ip_start + ip_len - 1) == ']')
+	{
+	  ++ip_start;
+	  ip_len -= 2;
+	}
+
       *server_ip = grub_malloc (ip_len + 1);
 
       if (!*server_ip)
@@ -591,8 +622,6 @@ find_bootfile_url (const struct grub_net
       *(*server_ip + ip_len) = '\0';
     }
 
-  path = ip_end + 1;
-
   if (boot_file)
     {
       *boot_file = grub_strdup (path);
@@ -747,8 +776,8 @@ grub_net_configure_by_dhcpv6_adv (const
   popt = (struct grub_dhcpv6_option*) nb->data;
   popt->code = grub_cpu_to_be16 (OPTION_ORO);
   popt->len = grub_cpu_to_be16 (4);
-  *((grub_uint16_t *) popt->data) = grub_cpu_to_be16 (OPTION_BOOTFILE_URL);
-  *((grub_uint16_t *) (popt->data + 2)) = grub_cpu_to_be16 (OPTION_DNS_SERVERS);
+  grub_set_unaligned16 (popt->data, grub_cpu_to_be16 (OPTION_BOOTFILE_URL));
+  grub_set_unaligned16 (popt->data + 2, grub_cpu_to_be16 (OPTION_DNS_SERVERS));
 
   err = grub_netbuff_push (nb, 6);
   if (err)
@@ -766,7 +795,7 @@ grub_net_configure_by_dhcpv6_adv (const
   if (elapsed > 0xffff)
     elapsed = 0xffff;
 
-  *((grub_uint16_t *) popt->data) = grub_cpu_to_be16 ((grub_uint16_t)elapsed);
+  grub_set_unaligned16 (popt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed));
 
   err = grub_netbuff_push (nb, 4);
   if (err)
@@ -1381,7 +1410,7 @@ grub_cmd_bootp6 (struct grub_command *cm
 	  opt = (struct grub_dhcpv6_option *)nb->data;
 	  opt->code = grub_cpu_to_be16 (OPTION_ELAPSED_TIME);
 	  opt->len = grub_cpu_to_be16 (2);
-	  *((grub_uint16_t *) opt->data) = 0;
+          grub_set_unaligned16 (opt->data, 0);
 
 	  err = grub_netbuff_push (nb, sizeof(*duid) + 4);
 	  if (err)
Index: grub-2.02~beta2/grub-core/net/drivers/efi/efinet.c
===================================================================
--- grub-2.02~beta2.orig/grub-core/net/drivers/efi/efinet.c
+++ grub-2.02~beta2/grub-core/net/drivers/efi/efinet.c
@@ -23,12 +23,15 @@
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
 #include <grub/i18n.h>
+#include <grub/net/netbuff.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
 /* GUID.  */
 static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
 static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
 
 static grub_err_t
 send_card_buffer (struct grub_net_card *dev,
@@ -364,6 +367,380 @@ grub_efinet_findcards (void)
   grub_free (handles);
 }
 
+static grub_efi_handle_t
+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
+			    grub_efi_device_path_t **r_device_path)
+{
+  grub_efi_handle_t handle;
+  grub_efi_status_t status;
+
+  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
+		      protocol, &device_path, &handle);
+
+  if (status != GRUB_EFI_SUCCESS)
+    return 0;
+
+  if (r_device_path)
+    *r_device_path = device_path;
+
+  return handle;
+}
+
+static grub_efi_ipv4_address_t *
+grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
+{
+  grub_efi_handle_t hnd;
+  grub_efi_status_t status;
+  grub_efi_ip4_config2_protocol_t *conf;
+  grub_efi_ipv4_address_t *addrs;
+  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t);
+
+  hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL);
+
+  if (!hnd)
+    return 0;
+
+  conf = grub_efi_open_protocol (hnd, &ip4_config_guid,
+				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+  if (!conf)
+    return 0;
+
+  addrs  = grub_malloc (data_size);
+  if (!addrs)
+    return 0;
+
+  status = efi_call_4 (conf->get_data, conf,
+		      GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+		      &data_size, addrs);
+
+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+    {
+      grub_free (addrs);
+      addrs  = grub_malloc (data_size);
+      if (!addrs)
+	return 0;
+
+      status = efi_call_4 (conf->get_data,  conf,
+			  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+			  &data_size, addrs);
+    }
+
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_free (addrs);
+      return 0;
+    }
+
+  *num_dns = data_size / sizeof (grub_efi_ipv4_address_t);
+  return addrs;
+}
+
+static grub_efi_ipv6_address_t *
+grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
+{
+  grub_efi_handle_t hnd;
+  grub_efi_status_t status;
+  grub_efi_ip6_config_protocol_t *conf;
+  grub_efi_ipv6_address_t *addrs;
+  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t);
+
+  hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL);
+
+  if (!hnd)
+    return 0;
+
+  conf = grub_efi_open_protocol (hnd, &ip6_config_guid,
+				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+  if (!conf)
+    return 0;
+
+  addrs  = grub_malloc (data_size);
+  if (!addrs)
+    return 0;
+
+  status = efi_call_4 (conf->get_data, conf,
+		      GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+		      &data_size, addrs);
+
+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+    {
+      grub_free (addrs);
+      addrs  = grub_malloc (data_size);
+      if (!addrs)
+	return 0;
+
+      status = efi_call_4 (conf->get_data,  conf,
+			  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+			  &data_size, addrs);
+    }
+
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_free (addrs);
+      return 0;
+    }
+
+  *num_dns = data_size / sizeof (grub_efi_ipv6_address_t);
+  return addrs;
+}
+
+static struct grub_net_buff *
+grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
+{
+  grub_efi_uint16_t uri_len;
+  grub_efi_device_path_t *ldp, *ddp;
+  grub_efi_uri_device_path_t *uri_dp;
+  struct grub_net_buff *nb;
+  grub_err_t err;
+
+  ddp = grub_efi_duplicate_device_path (dp);
+  ldp = grub_efi_find_last_device_path (ddp);
+
+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+      || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
+    {
+      grub_free (ddp);
+      return NULL;
+    }
+
+  uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4  : 0;
+
+  if (!uri_len)
+    {
+      grub_free (ddp);
+      return NULL;
+    }
+
+  uri_dp = (grub_efi_uri_device_path_t *) ldp;
+
+  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+  ldp->length = sizeof (*ldp);
+
+  ldp = grub_efi_find_last_device_path (ddp);
+
+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+      || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+          && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+    {
+      grub_free (ddp);
+      return NULL;
+    }
+
+  nb = grub_netbuff_alloc (512);
+  if (!nb)
+    return NULL;
+
+  if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
+    {
+      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
+      struct grub_net_bootp_packet *bp;
+      grub_uint8_t *ptr;
+      grub_efi_ipv4_address_t *dns;
+      grub_efi_uintn_t num_dns;
+
+      bp = (struct grub_net_bootp_packet *) nb->tail;
+      err = grub_netbuff_put (nb, sizeof (*bp) + 4);
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+
+      if (sizeof(bp->boot_file) < uri_len)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
+      grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
+      grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
+
+      bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
+      bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
+      bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
+      bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
+
+      ptr = nb->tail;
+      err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      *ptr++ = GRUB_NET_BOOTP_NETMASK;
+      *ptr++ = sizeof (ipv4->subnet_mask);
+      grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
+
+      ptr = nb->tail;
+      err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      *ptr++ = GRUB_NET_BOOTP_ROUTER;
+      *ptr++ = sizeof (ipv4->gateway_ip_address);
+      grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
+
+      ptr = nb->tail;
+      err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
+      *ptr++ = sizeof ("HTTPClient") - 1;
+      grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
+
+      dns = grub_dns_server_ip4_address (dp, &num_dns);
+      if (dns)
+	{
+  	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
+
+	  ptr = nb->tail;
+	  err = grub_netbuff_put (nb, size_dns + 2);
+	  if (err)
+	    {
+	      grub_free (ddp);
+	      grub_netbuff_free (nb);
+	      return NULL;
+	    }
+	  *ptr++ = GRUB_NET_BOOTP_DNS;
+	  *ptr++ = size_dns;
+	  grub_memcpy (ptr, dns, size_dns);
+	}
+
+      ptr = nb->tail;
+      err = grub_netbuff_put (nb, 1);
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      *ptr = 0xff;
+      *use_ipv6 = 0;
+
+      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+      ldp->length = sizeof (*ldp);
+      ldp = grub_efi_find_last_device_path (ddp);
+
+      if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) ==  GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
+	{
+	  grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
+	  bp->hw_type = mac->if_type;
+	  bp->hw_len = sizeof (bp->mac_addr);
+	  grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
+	}
+    }
+  else
+    {
+      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
+
+      struct grub_net_dhcpv6_packet *d6p;
+      struct grub_dhcpv6_option *opt;
+      struct grub_dhcpv6_iana_option *iana;
+      struct grub_dhcpv6_iaaddr_option *iaaddr;
+      grub_efi_ipv6_address_t *dns;
+      grub_efi_uintn_t num_dns;
+
+      d6p = (struct grub_net_dhcpv6_packet *)nb->tail;
+      err = grub_netbuff_put (nb, sizeof(*d6p));
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      d6p->message_type = DHCPv6_REPLY;
+
+      opt = (struct grub_dhcpv6_option *)nb->tail;
+      err = grub_netbuff_put (nb, sizeof(*opt));
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      opt->code = grub_cpu_to_be16_compile_time (OPTION_IA_NA);
+      opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
+
+      err = grub_netbuff_put (nb, sizeof(*iana));
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+
+      opt = (struct grub_dhcpv6_option *)nb->tail;
+      err = grub_netbuff_put (nb, sizeof(*opt));
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      opt->code = grub_cpu_to_be16_compile_time (OPTION_IAADDR);
+      opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
+
+      iaaddr = (struct grub_dhcpv6_iaaddr_option *)nb->tail;
+      err = grub_netbuff_put (nb, sizeof(*iaaddr));
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
+
+      opt = (struct grub_dhcpv6_option *)nb->tail;
+      err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
+      if (err)
+	{
+	  grub_free (ddp);
+	  grub_netbuff_free (nb);
+	  return NULL;
+	}
+      opt->code = grub_cpu_to_be16_compile_time (OPTION_BOOTFILE_URL);
+      opt->len = grub_cpu_to_be16 (uri_len);
+      grub_memcpy (opt->data, uri_dp->uri, uri_len);
+
+      dns = grub_dns_server_ip6_address (dp, &num_dns);
+      if (dns)
+	{
+  	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
+
+	  opt = (struct grub_dhcpv6_option *)nb->tail;
+	  err = grub_netbuff_put (nb, sizeof(*opt) + size_dns);
+	  if (err)
+	  {
+	    grub_free (ddp);
+	    grub_netbuff_free (nb);
+	    return NULL;
+	  }
+	  opt->code = grub_cpu_to_be16_compile_time (OPTION_DNS_SERVERS);
+	  opt->len = grub_cpu_to_be16_compile_time (size_dns);
+	  grub_memcpy (opt->data, dns, size_dns);
+	}
+
+      *use_ipv6 = 1;
+    }
+
+  return nb;
+}
+
+
 static void
 grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
 			  char **path)
@@ -380,6 +757,11 @@ grub_efi_net_config_real (grub_efi_handl
     grub_efi_device_path_t *cdp;
     struct grub_efi_pxe *pxe;
     struct grub_efi_pxe_mode *pxe_mode;
+    grub_uint8_t *dhcp_ack;
+    grub_size_t dhcp_ack_size ;
+    int ipv6;
+    struct grub_net_buff *nb = NULL;
+
     if (card->driver != &efidriver)
       continue;
     cdp = grub_efi_get_device_path (card->efi_handle);
@@ -399,11 +781,21 @@ grub_efi_net_config_real (grub_efi_handl
 	ldp = grub_efi_find_last_device_path (dp);
 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
-		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
 	  continue;
 	dup_dp = grub_efi_duplicate_device_path (dp);
 	if (!dup_dp)
 	  continue;
+
+	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
+	  {
+	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
+	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+	    dup_ldp->length = sizeof (*dup_ldp);
+	  }
+
 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
@@ -415,29 +807,44 @@ grub_efi_net_config_real (grub_efi_handl
       }
     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-    if (! pxe)
-      continue;
-    pxe_mode = pxe->mode;
+    if (!pxe)
+      {
+	nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
+	if (!nb)
+	  continue;
+	dhcp_ack = nb->head;
+	dhcp_ack_size = nb->tail - nb->head;
+      }
+    else
+      {
+	pxe_mode = pxe->mode;
+	dhcp_ack = (grub_uint8_t *) &pxe_mode->dhcp_ack;
+	dhcp_ack_size = sizeof (pxe_mode->dhcp_ack);
+	ipv6 = pxe_mode->using_ipv6;
+      }
 
-    if (pxe_mode->using_ipv6)
+    if (ipv6)
       {
 	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
 					    (struct grub_net_dhcpv6_packet *)
-					    &pxe_mode->dhcp_ack,
-					    sizeof (pxe_mode->dhcp_ack),
+					    dhcp_ack,
+					    dhcp_ack_size,
 					    1, device, path);
 	if (grub_errno)
 	  grub_print_error ();
-	return;
       }
     else
       {
 	grub_net_configure_by_dhcp_ack (card->name, card, 0,
 					(struct grub_net_bootp_packet *)
-					&pxe_mode->dhcp_ack,
-					sizeof (pxe_mode->dhcp_ack),
+					dhcp_ack,
+					dhcp_ack_size,
 					1, device, path);
       }
+
+    if (nb)
+      grub_netbuff_free (nb);
+
     return;
   }
 }
Index: grub-2.02~beta2/grub-core/net/http.c
===================================================================
--- grub-2.02~beta2.orig/grub-core/net/http.c
+++ grub-2.02~beta2/grub-core/net/http.c
@@ -312,24 +312,49 @@ http_establish (struct grub_file *file,
   int i;
   struct grub_net_buff *nb;
   grub_err_t err;
+  grub_net_network_level_netaddress_t addr;
+  char *host;
+
+  grub_error_push ();
+  err = grub_net_resolve_net_address (file->device->net->server, &addr);
+  grub_error_pop ();
+
+  if (err == GRUB_ERR_NONE &&
+      addr.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 &&
+      addr.ipv6.masksize == 128)
+    {
+      int hostsz = grub_strlen (file->device->net->server) + 3;
+      host = grub_malloc (hostsz);
+      if (host)
+	grub_snprintf (host, hostsz, "[%s]", file->device->net->server);
+    }
+  else
+    host = grub_strdup (file->device->net->server);
+
+  if (!host)
+    return grub_errno;
 
   nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
 			   + sizeof ("GET ") - 1
 			   + grub_strlen (data->filename)
 			   + sizeof (" HTTP/1.1\r\nHost: ") - 1
-			   + grub_strlen (file->device->net->server)
+			   + grub_strlen (host)
 			   + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
 				     "\r\n") - 1
 			   + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
 				     "-\r\n\r\n"));
   if (!nb)
-    return grub_errno;
+    {
+      grub_free (host);
+      return grub_errno;
+    }
 
   grub_netbuff_reserve (nb, GRUB_NET_TCP_RESERVE_SIZE);
   ptr = nb->tail;
   err = grub_netbuff_put (nb, sizeof ("GET ") - 1);
   if (err)
     {
+      grub_free (host);
       grub_netbuff_free (nb);
       return err;
     }
@@ -340,6 +365,7 @@ http_establish (struct grub_file *file,
   err = grub_netbuff_put (nb, grub_strlen (data->filename));
   if (err)
     {
+      grub_free (host);
       grub_netbuff_free (nb);
       return err;
     }
@@ -349,6 +375,7 @@ http_establish (struct grub_file *file,
   err = grub_netbuff_put (nb, sizeof (" HTTP/1.1\r\nHost: ") - 1);
   if (err)
     {
+      grub_free (host);
       grub_netbuff_free (nb);
       return err;
     }
@@ -356,14 +383,15 @@ http_establish (struct grub_file *file,
 	       sizeof (" HTTP/1.1\r\nHost: ") - 1);
 
   ptr = nb->tail;
-  err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
+  err = grub_netbuff_put (nb, grub_strlen (host));
   if (err)
     {
+      grub_free (host);
       grub_netbuff_free (nb);
       return err;
     }
-  grub_memcpy (ptr, file->device->net->server,
-	       grub_strlen (file->device->net->server));
+  grub_memcpy (ptr, host, grub_strlen (host));
+  grub_free (host);
 
   ptr = nb->tail;
   err = grub_netbuff_put (nb, 
@@ -381,9 +409,8 @@ http_establish (struct grub_file *file,
       ptr = nb->tail;
       grub_snprintf ((char *) ptr,
 		     sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX-"
-			     "\r\n"
 			     "\r\n"),
-		     "Range: bytes=%" PRIuGRUB_UINT64_T "-\r\n\r\n",
+		     "Range: bytes=%" PRIuGRUB_UINT64_T "-\r\n",
 		     offset);
       grub_netbuff_put (nb, grub_strlen ((char *) ptr));
     }
Index: grub-2.02~beta2/include/grub/efi/api.h
===================================================================
--- grub-2.02~beta2.orig/include/grub/efi/api.h
+++ grub-2.02~beta2/include/grub/efi/api.h
@@ -286,6 +286,16 @@
       { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \
   }
 
+#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \
+  { 0x5b446ed1, 0xe30b, 0x4faa, \
+      { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
+  }
+
+#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \
+  { 0x937fe521, 0x95ae, 0x4d1a, \
+      { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
+  }
+
 struct grub_efi_sal_system_table
 {
   grub_uint32_t signature;
@@ -776,6 +786,8 @@ struct grub_efi_ipv4_device_path
   grub_efi_uint16_t remote_port;
   grub_efi_uint16_t protocol;
   grub_efi_uint8_t static_ip_address;
+  grub_efi_ipv4_address_t gateway_ip_address;
+  grub_efi_ipv4_address_t subnet_mask;
 } GRUB_PACKED;
 typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t;
 
@@ -830,6 +842,15 @@ struct grub_efi_sata_device_path
 } GRUB_PACKED;
 typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t;
 
+#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE		24
+
+struct grub_efi_uri_device_path
+{
+  grub_efi_device_path_t header;
+  grub_efi_uint8_t uri[0];
+} GRUB_PACKED;
+typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
+
 #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
 
 /* Media Device Path.  */
@@ -1627,6 +1648,72 @@ struct grub_efi_block_io
 };
 typedef struct grub_efi_block_io grub_efi_block_io_t;
 
+enum grub_efi_ip4_config2_data_type {
+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM
+};
+typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t;
+
+struct grub_efi_ip4_config2_protocol
+{
+  grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this,
+				 grub_efi_ip4_config2_data_type_t data_type,
+				 grub_efi_uintn_t data_size,
+				 void *data);
+
+  grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this,
+				 grub_efi_ip4_config2_data_type_t data_type,
+				 grub_efi_uintn_t *data_size,
+				 void *data);
+
+  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this,
+					     grub_efi_ip4_config2_data_type_t data_type,
+					     grub_efi_event_t event);
+
+  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this,
+					     grub_efi_ip4_config2_data_type_t data_type,
+					     grub_efi_event_t event);
+};
+typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
+
+enum grub_efi_ip6_config_data_type {
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM
+};
+typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t;
+
+struct grub_efi_ip6_config_protocol
+{
+  grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this,
+				 grub_efi_ip6_config_data_type_t data_type,
+				 grub_efi_uintn_t data_size,
+				 void *data);
+
+  grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this,
+				 grub_efi_ip6_config_data_type_t data_type,
+				 grub_efi_uintn_t *data_size,
+				 void *data);
+
+  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this,
+					     grub_efi_ip6_config_data_type_t data_type,
+					     grub_efi_event_t event);
+
+  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this,
+					     grub_efi_ip6_config_data_type_t data_type,
+					     grub_efi_event_t event);
+};
+typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
+
 #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
 
Index: grub-2.02~beta2/include/grub/net.h
===================================================================
--- grub-2.02~beta2.orig/include/grub/net.h
+++ grub-2.02~beta2/include/grub/net.h
@@ -433,6 +433,53 @@ struct grub_net_dhcpv6_packet
   grub_uint8_t dhcp_options[0];
 } GRUB_PACKED;
 
+struct grub_dhcpv6_option {
+  grub_uint16_t code;
+  grub_uint16_t len;
+  grub_uint8_t data[0];
+} GRUB_PACKED;
+
+struct grub_dhcpv6_iana_option {
+  grub_uint32_t iaid;
+  grub_uint32_t t1;
+  grub_uint32_t t2;
+  grub_uint8_t data[0];
+} GRUB_PACKED;
+
+struct grub_dhcpv6_iaaddr_option {
+  grub_uint8_t addr[16];
+  grub_uint32_t preferred_lifetime;
+  grub_uint32_t valid_lifetime;
+  grub_uint8_t data[0];
+} GRUB_PACKED;
+
+struct grub_DUID_LL
+{
+  grub_uint16_t type;
+  grub_uint16_t hw_type;
+  grub_uint8_t hwaddr[6];
+} GRUB_PACKED;
+
+struct grub_dhcpv6_dns_servers {
+  grub_uint8_t addr[16];
+  grub_uint8_t next_addr[0];
+} GRUB_PACKED;
+
+//http://tools.ietf.org/html/rfc1035#section-3.1
+
+#define DHCPv6_REPLY 7
+#define DHCPv6_ADVERTISE 2
+#define DHCPv6_REQUEST 3
+#define OPTION_BOOTFILE_URL 59
+//RFC3646 http://tools.ietf.org/html/rfc3646
+#define OPTION_DNS_SERVERS 23
+#define OPTION_IA_NA 3
+#define OPTION_IAADDR 5
+#define OPTION_CLIENTID 1
+#define OPTION_SERVERID 2
+#define OPTION_ORO 6
+#define OPTION_ELAPSED_TIME 8
+
 #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
 #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
 #define	GRUB_NET_BOOTP_RFC1048_MAGIC_2	0x53
@@ -448,6 +495,7 @@ enum
     GRUB_NET_BOOTP_DOMAIN = 0x0f,
     GRUB_NET_BOOTP_ROOT_PATH = 0x11,
     GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
+    GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 0x3C,
     GRUB_NET_BOOTP_END = 0xff
   };