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