Blame SOURCES/0172-send-router-solicitation-for-ipv6-address-autoconf-v.patch

4fe85b
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
4fe85b
From: Michael Chang <mchang@suse.com>
4fe85b
Date: Tue, 18 Nov 2014 16:03:08 +0800
4fe85b
Subject: [PATCH] send router solicitation for ipv6 address autoconf v2
4fe85b
4fe85b
Many routers have long router advertisment interval configured by
4fe85b
default. The Neighbor Discovery protocol (RFC4861) has defined default
4fe85b
MaxRtrAdvInterval value as 600 seconds and
4fe85b
MinRtrAdvInterval as 0.33*MaxRtrAdvInterval. This makes
4fe85b
net_ipv6_autoconf fails more often than not as currently it passively
4fe85b
listens the RA message to perfom address autoconfiguration.
4fe85b
4fe85b
This patch tries to send router solicitation to overcome the problem of
4fe85b
long RA interval.
4fe85b
4fe85b
v2:
4fe85b
use cpu_to_be macro for network byte order conversion
4fe85b
add missing error handling
4fe85b
---
4fe85b
 grub-core/net/icmp6.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
4fe85b
 grub-core/net/net.c   |  4 ++-
4fe85b
 include/grub/net/ip.h |  2 ++
4fe85b
 3 files changed, 88 insertions(+), 1 deletion(-)
4fe85b
4fe85b
diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
4fe85b
index bbc902014fe..0843a15afda 100644
4fe85b
--- a/grub-core/net/icmp6.c
4fe85b
+++ b/grub-core/net/icmp6.c
4fe85b
@@ -72,6 +72,11 @@ struct neighbour_advertise
4fe85b
   grub_uint64_t target[2];
4fe85b
 } GRUB_PACKED;
4fe85b
 
4fe85b
+struct router_solicit
4fe85b
+{
4fe85b
+  grub_uint32_t reserved;
4fe85b
+} GRUB_PACKED;
4fe85b
+
4fe85b
 enum
4fe85b
   {
4fe85b
     FLAG_SLAAC = 0x40
4fe85b
@@ -81,6 +86,7 @@ enum
4fe85b
   {
4fe85b
     ICMP6_ECHO = 128,
4fe85b
     ICMP6_ECHO_REPLY = 129,
4fe85b
+    ICMP6_ROUTER_SOLICIT = 133,
4fe85b
     ICMP6_ROUTER_ADVERTISE = 134,
4fe85b
     ICMP6_NEIGHBOUR_SOLICIT = 135,
4fe85b
     ICMP6_NEIGHBOUR_ADVERTISE = 136,
4fe85b
@@ -533,3 +539,80 @@ grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf,
4fe85b
   grub_netbuff_free (nb);
4fe85b
   return err;
4fe85b
 }
4fe85b
+
4fe85b
+grub_err_t
4fe85b
+grub_net_icmp6_send_router_solicit (struct grub_net_network_level_interface *inf)
4fe85b
+{
4fe85b
+  struct grub_net_buff *nb;
4fe85b
+  grub_err_t err = GRUB_ERR_NONE;
4fe85b
+  grub_net_network_level_address_t multicast;
4fe85b
+  grub_net_link_level_address_t ll_multicast;
4fe85b
+  struct option_header *ohdr;
4fe85b
+  struct router_solicit *sol;
4fe85b
+  struct icmp_header *icmphr;
4fe85b
+
4fe85b
+  multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
4fe85b
+  multicast.ipv6[0] = grub_cpu_to_be64 (0xff02ULL << 48);
4fe85b
+  multicast.ipv6[1] = grub_cpu_to_be64 (0x02ULL);
4fe85b
+
4fe85b
+  err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
4fe85b
+  if (err)
4fe85b
+    return err;
4fe85b
+
4fe85b
+  nb = grub_netbuff_alloc (sizeof (struct router_solicit)
4fe85b
+			   + sizeof (struct option_header)
4fe85b
+			   + 6
4fe85b
+			   + sizeof (struct icmp_header)
4fe85b
+			   + GRUB_NET_OUR_IPV6_HEADER_SIZE
4fe85b
+			   + GRUB_NET_MAX_LINK_HEADER_SIZE);
4fe85b
+  if (!nb)
4fe85b
+    return grub_errno;
4fe85b
+  err = grub_netbuff_reserve (nb,
4fe85b
+			      sizeof (struct router_solicit)
4fe85b
+			      + sizeof (struct option_header)
4fe85b
+			      + 6
4fe85b
+			      + sizeof (struct icmp_header)
4fe85b
+			      + GRUB_NET_OUR_IPV6_HEADER_SIZE
4fe85b
+			      + GRUB_NET_MAX_LINK_HEADER_SIZE);
4fe85b
+  if (err)
4fe85b
+    goto fail;
4fe85b
+
4fe85b
+  err = grub_netbuff_push (nb, 6);
4fe85b
+  if (err)
4fe85b
+    goto fail;
4fe85b
+
4fe85b
+  grub_memcpy (nb->data, inf->hwaddress.mac, 6);
4fe85b
+
4fe85b
+  err = grub_netbuff_push (nb, sizeof (*ohdr));
4fe85b
+  if (err)
4fe85b
+    goto fail;
4fe85b
+
4fe85b
+  ohdr = (struct option_header *) nb->data;
4fe85b
+  ohdr->type = OPTION_SOURCE_LINK_LAYER_ADDRESS;
4fe85b
+  ohdr->len = 1;
4fe85b
+
4fe85b
+  err = grub_netbuff_push (nb, sizeof (*sol));
4fe85b
+  if (err)
4fe85b
+    goto fail;
4fe85b
+
4fe85b
+  sol = (struct router_solicit *) nb->data;
4fe85b
+  sol->reserved = 0;
4fe85b
+
4fe85b
+  err = grub_netbuff_push (nb, sizeof (*icmphr));
4fe85b
+  if (err)
4fe85b
+    goto fail;
4fe85b
+
4fe85b
+  icmphr = (struct icmp_header *) nb->data;
4fe85b
+  icmphr->type = ICMP6_ROUTER_SOLICIT;
4fe85b
+  icmphr->code = 0;
4fe85b
+  icmphr->checksum = 0;
4fe85b
+  icmphr->checksum = grub_net_ip_transport_checksum (nb,
4fe85b
+						     GRUB_NET_IP_ICMPV6,
4fe85b
+						     &inf->address,
4fe85b
+						     &multicast);
4fe85b
+  err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
4fe85b
+				 GRUB_NET_IP_ICMPV6);
4fe85b
+ fail:
4fe85b
+  grub_netbuff_free (nb);
4fe85b
+  return err;
4fe85b
+}
4fe85b
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
4fe85b
index 10bfed31b2b..b10addbe27b 100644
4fe85b
--- a/grub-core/net/net.c
4fe85b
+++ b/grub-core/net/net.c
4fe85b
@@ -380,12 +380,14 @@ grub_cmd_ipv6_autoconf (struct grub_command *cmd __attribute__ ((unused)),
4fe85b
 
4fe85b
   for (interval = 200; interval < 10000; interval *= 2)
4fe85b
     {
4fe85b
-      /* FIXME: send router solicitation.  */
4fe85b
       int done = 1;
4fe85b
       for (j = 0; j < ncards; j++)
4fe85b
 	{
4fe85b
 	  if (slaacs[j]->slaac_counter)
4fe85b
 	    continue;
4fe85b
+	  err = grub_net_icmp6_send_router_solicit (ifaces[j]);
4fe85b
+	  if (err)
4fe85b
+	    err = GRUB_ERR_NONE;
4fe85b
 	  done = 0;
4fe85b
 	}
4fe85b
       if (done)
4fe85b
diff --git a/include/grub/net/ip.h b/include/grub/net/ip.h
4fe85b
index 7a8e614794d..dcceaa56894 100644
4fe85b
--- a/include/grub/net/ip.h
4fe85b
+++ b/include/grub/net/ip.h
4fe85b
@@ -92,4 +92,6 @@ grub_err_t
4fe85b
 grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf,
4fe85b
 			     const grub_net_network_level_address_t *proto_addr);
4fe85b
 
4fe85b
+grub_err_t
4fe85b
+grub_net_icmp6_send_router_solicit (struct grub_net_network_level_interface *inf);
4fe85b
 #endif