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