File grub2-bootp6-dns.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
@@ -285,10 +285,19 @@ struct grub_DUID_LL
   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
@@ -444,6 +453,52 @@ find_address (const struct grub_net_dhcp
 }
 
 static void
+get_dns_address (const struct grub_net_dhcpv6_packet *packet, grub_net_network_level_address_t **addr, grub_uint16_t *naddr)
+{
+  const struct grub_dhcpv6_option* popt;
+  const struct grub_dhcpv6_dns_servers *dns;
+  grub_uint16_t len;
+  const grub_uint8_t *pa;
+  int i, ln;
+  grub_net_network_level_address_t *la;
+
+  if (addr)
+    *addr = NULL;
+
+  if (naddr)
+    *naddr = 0;
+
+  popt = find_dhcpv6_option (packet, OPTION_DNS_SERVERS);
+  if (!popt)
+    return;
+
+  len = grub_be_to_cpu16 (popt->len);
+  if ((len % 16) != 0)
+    {
+      grub_error (GRUB_ERR_IO, N_("invalid dns address length"));
+      return;
+    }
+
+  dns = (const struct grub_dhcpv6_dns_servers *)popt->data;
+
+  ln = len / 16;
+  la = grub_zalloc (sizeof (grub_net_network_level_address_t) * ln);
+
+  for (i = 0, pa = dns->addr; i < ln; i++, pa = dns->next_addr)
+    {
+      (la + i)->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+      (la + i)->ipv6[0] = grub_get_unaligned64 (pa);
+      (la + i)->ipv6[1] = grub_get_unaligned64 (pa + 8);
+      (la + i)->option = DNS_OPTION_PREFER_IPV6;
+    }
+
+  *addr = la;
+  *naddr = ln;
+
+  return;
+}
+
+static void
 find_bootfile_url (const struct grub_net_dhcpv6_packet *packet,
 		    char **proto,
 		    char **server_ip,
@@ -682,7 +737,7 @@ grub_net_configure_by_dhcpv6_adv (const
     }
   grub_memcpy (nb->data, opt_iana, len + 4);
 
-  err = grub_netbuff_push (nb, 6);
+  err = grub_netbuff_push (nb, 8);
   if (err)
     {
       grub_netbuff_free (nb);
@@ -691,9 +746,9 @@ 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 (2);
+  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);
 
   err = grub_netbuff_push (nb, 6);
   if (err)
@@ -768,6 +823,8 @@ grub_net_configure_by_dhcpv6_reply (cons
   char *proto;
   char *server_ip;
   char *boot_file;
+  grub_net_network_level_address_t *dns;
+  grub_uint16_t num_dns;
 
   if (device)
     *device = NULL;
@@ -789,6 +846,23 @@ grub_net_configure_by_dhcpv6_reply (cons
       return NULL;
     }
 
+  get_dns_address (v6, &dns, &num_dns);
+
+  if (dns && num_dns)
+    {
+      int i;
+
+      for (i = 0; i < num_dns; ++i)
+	grub_net_add_dns_server (dns + i);
+
+      grub_free (dns);
+    }
+  else
+    {
+      if (grub_errno)
+	grub_print_error ();
+    }
+
   find_bootfile_url (v6, &proto, &server_ip, &boot_file);
 
   if (grub_errno)