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

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