diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index aa5f2bfe7..3827227b8 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1603,6 +1603,7 @@ module = {
common = net/udp.c;
common = net/tcp.c;
common = net/icmp.c;
+ common = net/icmp6.c;
common = net/ethernet.c;
common = net/arp.c;
common = net/netbuff.c;
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 3187f2e9c..1b8527255 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -130,7 +130,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
: sizeof (hwaddr.mac));
hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
- inter = grub_net_add_addr (name, card, addr, hwaddr, flags);
+ inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
if (bp->gateway_ip)
{
grub_net_network_level_netaddress_t target;
@@ -379,6 +379,7 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
"unrecognised format specification %s", args[3]);
}
+/* FIXME: allow to specify mac address. */
static grub_err_t
grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
index 053f87b56..8d7f66830 100644
--- a/grub-core/net/ethernet.c
+++ b/grub-core/net/ethernet.c
@@ -81,7 +81,7 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
grub_err_t
grub_net_recv_ethernet_packet (struct grub_net_buff * nb,
- const struct grub_net_card * card)
+ struct grub_net_card * card)
{
struct etherhdr *eth;
struct llchdr *llch;
@@ -123,11 +123,8 @@ grub_net_recv_ethernet_packet (struct grub_net_buff * nb,
return GRUB_ERR_NONE;
/* IP packet. */
case GRUB_NET_ETHERTYPE_IP:
- grub_net_recv_ip4_packets (nb, card, &hwaddress);
- return GRUB_ERR_NONE;
case GRUB_NET_ETHERTYPE_IP6:
- grub_net_recv_ip4_packets (nb, card, &hwaddress);
- return GRUB_ERR_NONE;
+ return grub_net_recv_ip_packets (nb, card, &hwaddress);
}
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
diff --git a/grub-core/net/icmp.c b/grub-core/net/icmp.c
index 8ea020107..88132b142 100644
--- a/grub-core/net/icmp.c
+++ b/grub-core/net/icmp.c
@@ -25,13 +25,13 @@ struct icmp_header
grub_uint8_t type;
grub_uint8_t code;
grub_uint16_t checksum;
-};
+} __attribute__ ((packed));
struct ping_header
{
grub_uint16_t id;
grub_uint16_t seq;
-};
+} __attribute__ ((packed));
enum
{
@@ -40,7 +40,7 @@ enum
};
grub_err_t
-grub_net_recv_icmp_packet (struct grub_net_buff * nb,
+grub_net_recv_icmp_packet (struct grub_net_buff *nb,
struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *src)
{
@@ -48,15 +48,28 @@ grub_net_recv_icmp_packet (struct grub_net_buff * nb,
grub_err_t err;
grub_uint16_t checksum;
+ /* Ignore broadcast. */
+ if (!inf)
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+
icmph = (struct icmp_header *) nb->data;
if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "ICMP packet too small");
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
checksum = icmph->checksum;
icmph->checksum = 0;
if (checksum != grub_net_ip_chksum (nb->data, nb->tail - nb->data))
- return GRUB_ERR_NONE;
+ {
+ icmph->checksum = checksum;
+ return GRUB_ERR_NONE;
+ }
icmph->checksum = checksum;
err = grub_netbuff_pull (nb, sizeof (*icmph));
diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
new file mode 100644
index 000000000..ac12c5733
--- /dev/null
+++ b/grub-core/net/icmp6.c
@@ -0,0 +1,235 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010,2011 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+
+struct icmp_header
+{
+ grub_uint8_t type;
+ grub_uint8_t code;
+ grub_uint16_t checksum;
+} __attribute__ ((packed));
+
+struct ping_header
+{
+ grub_uint16_t id;
+ grub_uint16_t seq;
+} __attribute__ ((packed));
+
+struct router_adv
+{
+ grub_uint8_t ttl;
+ grub_uint8_t flags;
+ grub_uint16_t router_lifetime;
+ grub_uint32_t reachable_time;
+ grub_uint32_t retrans_timer;
+ grub_uint8_t options[0];
+} __attribute__ ((packed));
+
+struct prefix_option
+{
+ grub_uint8_t type;
+ grub_uint8_t len;
+ grub_uint8_t prefixlen;
+ grub_uint8_t flags;
+ grub_uint32_t valid_lifetime;
+ grub_uint32_t prefered_lifetime;
+ grub_uint32_t reserved;
+ grub_uint64_t prefix[2];
+} __attribute__ ((packed));
+
+enum
+ {
+ FLAG_SLAAC = 0x40
+ };
+
+enum
+ {
+ ICMP6_ECHO = 128,
+ ICMP6_ECHO_REPLY = 129,
+ ICMP6_ROUTER_ADVERTISE = 134
+ };
+
+grub_err_t
+grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ struct grub_net_card *card,
+ struct grub_net_network_level_interface *inf,
+ const grub_net_network_level_address_t *source,
+ const grub_net_network_level_address_t *dest)
+{
+ struct icmp_header *icmph;
+ grub_err_t err;
+ grub_uint16_t checksum;
+
+ icmph = (struct icmp_header *) nb->data;
+
+ if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+
+ checksum = icmph->checksum;
+ icmph->checksum = 0;
+ if (checksum != grub_net_ip_transport_checksum (nb,
+ GRUB_NET_IP_ICMPV6,
+ source,
+ dest))
+ {
+ grub_dprintf ("net", "invalid ICMPv6 checksum: %04x instead of %04x\n",
+ checksum,
+ grub_net_ip_transport_checksum (nb,
+ GRUB_NET_IP_ICMPV6,
+ source,
+ dest));
+ icmph->checksum = checksum;
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+ icmph->checksum = checksum;
+
+ err = grub_netbuff_pull (nb, sizeof (*icmph));
+ if (err)
+ return err;
+
+ grub_dprintf ("net", "ICMPv6 message: %02x, %02x\n",
+ icmph->type, icmph->code);
+ switch (icmph->type)
+ {
+ case ICMP6_ECHO:
+ /* Don't accept multicast pings. */
+ if (!inf)
+ break;
+ {
+ struct grub_net_buff *nb_reply;
+ struct icmp_header *icmphr;
+ if (icmph->code)
+ break;
+ nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512);
+ if (!nb_reply)
+ {
+ grub_netbuff_free (nb);
+ return grub_errno;
+ }
+ err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512);
+ if (err)
+ goto ping_fail;
+ err = grub_netbuff_push (nb_reply, nb->tail - nb->data);
+ if (err)
+ goto ping_fail;
+ grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data);
+ err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
+ if (err)
+ goto ping_fail;
+ icmphr = (struct icmp_header *) nb_reply->data;
+ icmphr->type = ICMP6_ECHO_REPLY;
+ icmphr->code = 0;
+ icmphr->checksum = 0;
+ icmphr->checksum = grub_net_ip_transport_checksum (nb_reply,
+ GRUB_NET_IP_ICMPV6,
+ &inf->address,
+ source);
+ err = grub_net_send_ip_packet (inf, source, nb_reply,
+ GRUB_NET_IP_ICMPV6);
+
+ ping_fail:
+ grub_netbuff_free (nb);
+ grub_netbuff_free (nb_reply);
+ return err;
+ }
+ case ICMP6_ROUTER_ADVERTISE:
+ {
+ grub_uint8_t *ptr;
+ if (icmph->code)
+ break;
+ err = grub_netbuff_pull (nb, sizeof (struct router_adv));
+ if (err)
+ return err;
+ for (ptr = (grub_uint8_t *) nb->data + sizeof (struct router_adv);
+ ptr < nb->tail; )
+ {
+ grub_dprintf ("net", "option %02x, %02x\n", ptr[0], ptr[1]);
+ if (ptr + 2 >= nb->tail || ptr[1] == 0)
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+ if (ptr[0] == 3 && ptr[1] == 4)
+ {
+ struct prefix_option *opt = (struct prefix_option *) ptr;
+ struct grub_net_slaac_mac_list *slaac;
+ if (!(opt->flags & FLAG_SLAAC)
+ || (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80
+ || (grub_be_to_cpu32 (opt->prefered_lifetime)
+ > grub_be_to_cpu32 (opt->valid_lifetime))
+ || opt->prefixlen != 64)
+ {
+ ptr += ptr[1] * 8;
+ grub_dprintf ("net", "discarded prefix: %d, %d, %d, %d\n",
+ !(opt->flags & FLAG_SLAAC),
+ (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80,
+ (grub_be_to_cpu32 (opt->prefered_lifetime)
+ > grub_be_to_cpu32 (opt->valid_lifetime)),
+ opt->prefixlen != 64);
+ continue;
+ }
+ for (slaac = card->slaac_list; slaac; slaac = slaac->next)
+ {
+ grub_net_network_level_address_t addr;
+ if (slaac->address.type
+ != GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET)
+ continue;
+ addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ addr.ipv6[0] = opt->prefix[0];
+ addr.ipv6[1] = grub_net_ipv6_get_id (&slaac->address);
+ FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+ {
+ if (inf->card == card
+ && grub_net_addr_cmp (&inf->address, &addr) == 0)
+ break;
+ }
+ /* Update lease time if needed here once we have
+ lease times. */
+ if (inf)
+ continue;
+
+ grub_dprintf ("net", "creating slaac\n");
+
+ {
+ char name[grub_strlen (slaac->name)
+ + sizeof (":XXXXXXXXXXXXXXXXXXXX")];
+ grub_snprintf (name, sizeof (name), "%s:%d",
+ slaac->name, slaac->slaac_counter++);
+ grub_net_add_addr (name,
+ card, &addr,
+ &slaac->address, 0);
+ }
+ }
+ }
+ ptr += ptr[1] * 8;
+ }
+ if (ptr != nb->tail)
+ break;
+ }
+ };
+
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
index 32a7d7fe7..18593da49 100644
--- a/grub-core/net/ip.c
+++ b/grub-core/net/ip.c
@@ -221,7 +221,7 @@ grub_net_send_ip4_packet (struct grub_net_network_level_interface * inf,
static grub_err_t
handle_dgram (struct grub_net_buff *nb,
- const struct grub_net_card *card,
+ struct grub_net_card *card,
const grub_net_link_level_address_t *hwaddress,
grub_net_ip_protocol_t proto,
const grub_net_network_level_address_t *source,
@@ -282,8 +282,12 @@ handle_dgram (struct grub_net_buff *nb,
break;
}
- if (!inf)
+ if (!inf && !(dest->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
+ && dest->ipv6[0] == grub_be_to_cpu64 (0xff02ULL << 48)
+ && dest->ipv6[1] == grub_be_to_cpu64 (1)))
{
+ grub_dprintf ("net", "undirected dgram discarded: %x, %lx, %lx\n",
+ dest->type, dest->ipv6[0], dest->ipv6[1]);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
@@ -296,6 +300,8 @@ handle_dgram (struct grub_net_buff *nb,
return grub_net_recv_tcp_packet (nb, inf, source);
case GRUB_NET_IP_ICMP:
return grub_net_recv_icmp_packet (nb, inf, source);
+ case GRUB_NET_IP_ICMPV6:
+ return grub_net_recv_icmp6_packet (nb, card, inf, source, dest);
default:
grub_netbuff_free (nb);
break;
@@ -330,9 +336,9 @@ free_old_fragments (void)
}
}
-grub_err_t
+static grub_err_t
grub_net_recv_ip4_packets (struct grub_net_buff * nb,
- const struct grub_net_card * card,
+ struct grub_net_card * card,
const grub_net_link_level_address_t * hwaddress)
{
struct iphdr *iph = (struct iphdr *) nb->data;
@@ -590,12 +596,11 @@ grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
default:
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP");
}
-
}
-grub_err_t
+static grub_err_t
grub_net_recv_ip6_packets (struct grub_net_buff * nb,
- const struct grub_net_card * card,
+ struct grub_net_card * card,
const grub_net_link_level_address_t * hwaddress)
{
struct ip6hdr *iph = (struct ip6hdr *) nb->data;
@@ -652,8 +657,24 @@ grub_net_recv_ip6_packets (struct grub_net_buff * nb,
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
grub_memcpy (source.ipv6, &iph->src, sizeof (source.ipv6));
- grub_memcpy (dest.ipv6, &iph->src, sizeof (dest.ipv6));
+ grub_memcpy (dest.ipv6, &iph->dest, sizeof (dest.ipv6));
return handle_dgram (nb, card, hwaddress, iph->protocol,
&source, &dest);
}
+
+grub_err_t
+grub_net_recv_ip_packets (struct grub_net_buff * nb,
+ struct grub_net_card * card,
+ const grub_net_link_level_address_t * hwaddress)
+{
+ struct iphdr *iph = (struct iphdr *) nb->data;
+
+ if ((iph->verhdrlen >> 4) == 4)
+ return grub_net_recv_ip4_packets (nb, card, hwaddress);
+ if ((iph->verhdrlen >> 4) == 6)
+ return grub_net_recv_ip6_packets (nb, card, hwaddress);
+ grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4));
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 398e6f5ae..1c6d47757 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -72,6 +73,151 @@ grub_net_card_unregister (struct grub_net_card *card)
GRUB_AS_LIST (card));
}
+static struct grub_net_slaac_mac_list *
+grub_net_ipv6_get_slaac (struct grub_net_card *card,
+ const grub_net_link_level_address_t *hwaddr)
+{
+ struct grub_net_slaac_mac_list *slaac;
+ char *ptr;
+
+ for (slaac = card->slaac_list; slaac; slaac = slaac->next)
+ if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0)
+ return slaac;
+
+ slaac = grub_zalloc (sizeof (*slaac));
+ if (!slaac)
+ return NULL;
+
+ slaac->name = grub_malloc (grub_strlen (card->name)
+ + GRUB_NET_MAX_STR_HWADDR_LEN
+ + sizeof (":slaac"));
+ ptr = grub_stpcpy (slaac->name, card->name);
+ if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
+ {
+ ptr = grub_stpcpy (ptr, ":");
+ grub_net_hwaddr_to_str (hwaddr, ptr);
+ ptr += grub_strlen (ptr);
+ }
+ ptr = grub_stpcpy (ptr, ":slaac");
+
+ grub_memcpy (&slaac->address, hwaddr, sizeof (slaac->address));
+ slaac->next = card->slaac_list;
+ card->slaac_list = slaac;
+ return slaac;
+}
+
+struct grub_net_network_level_interface *
+grub_net_ipv6_get_link_local (struct grub_net_card *card,
+ const grub_net_link_level_address_t *hwaddr)
+{
+ struct grub_net_network_level_interface *inf;
+ char name[grub_strlen (card->name)
+ + GRUB_NET_MAX_STR_HWADDR_LEN
+ + sizeof (":link")];
+ char *ptr;
+ grub_net_network_level_address_t addr;
+
+ addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ addr.ipv6[0] = grub_cpu_to_be64 (0xfe80ULL << 48);
+ addr.ipv6[1] = grub_net_ipv6_get_id (hwaddr);
+
+ FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+ {
+ if (inf->card == card
+ && grub_net_hwaddr_cmp (&inf->hwaddress, hwaddr) == 0
+ && grub_net_addr_cmp (&inf->address, &addr) == 0)
+ return inf;
+ }
+
+ ptr = grub_stpcpy (name, card->name);
+ if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
+ {
+ ptr = grub_stpcpy (ptr, ":");
+ grub_net_hwaddr_to_str (hwaddr, ptr);
+ ptr += grub_strlen (ptr);
+ }
+ ptr = grub_stpcpy (ptr, ":link");
+ return grub_net_add_addr (name, card, &addr, hwaddr, 0);
+}
+
+/* FIXME: allow to specify mac address. */
+static grub_err_t
+grub_cmd_ipv6_autoconf (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_net_card *card;
+ struct grub_net_network_level_interface **ifaces;
+ grub_size_t ncards = 0;
+ unsigned j = 0;
+ int interval;
+ grub_err_t err;
+ struct grub_net_slaac_mac_list **slaacs;
+
+ FOR_NET_CARDS (card)
+ {
+ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
+ continue;
+ ncards++;
+ }
+
+ ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
+ slaacs = grub_zalloc (ncards * sizeof (slaacs[0]));
+ if (!ifaces || !slaacs)
+ {
+ grub_free (ifaces);
+ grub_free (slaacs);
+ return grub_errno;
+ }
+
+ FOR_NET_CARDS (card)
+ {
+ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
+ continue;
+ ifaces[j] = grub_net_ipv6_get_link_local (card, &card->default_address);
+ if (!ifaces[j])
+ {
+ grub_free (ifaces);
+ grub_free (slaacs);
+ return grub_errno;
+ }
+ slaacs[j] = grub_net_ipv6_get_slaac (card, &card->default_address);
+ if (!slaacs[j])
+ {
+ grub_free (ifaces);
+ grub_free (slaacs);
+ return grub_errno;
+ }
+ j++;
+ }
+
+ 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;
+ done = 0;
+ }
+ if (done)
+ break;
+ grub_net_poll_cards (interval);
+ }
+
+ err = GRUB_ERR_NONE;
+ for (j = 0; j < ncards; j++)
+ {
+ if (slaacs[j]->slaac_counter)
+ continue;
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s",
+ ifaces[j]->card->name);
+ }
+
+ grub_free (ifaces);
+ grub_free (slaacs);
+ return err;
+}
static inline void
grub_net_route_register (struct grub_net_route *route)
@@ -265,20 +411,22 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
{
char *ptr = buf;
- grub_uint32_t n = grub_be_to_cpu32 (target->ipv6[0]);
+ grub_uint64_t n = grub_be_to_cpu64 (target->ipv6[0]);
int i;
for (i = 0; i < 4; i++)
{
- grub_snprintf (ptr, 6, "%x:", (n >> (48 - 16 * i)) & 0xffff);
+ grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":",
+ (n >> (48 - 16 * i)) & 0xffff);
ptr += grub_strlen (ptr);
}
- n = grub_be_to_cpu32 (target->ipv6[1]);
+ n = grub_be_to_cpu64 (target->ipv6[1]);
for (i = 0; i < 3; i++)
{
- grub_snprintf (ptr, 6, "%x:", (n >> (48 - 16 * i)) & 0xffff);
+ grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":",
+ (n >> (48 - 16 * i)) & 0xffff);
ptr += grub_strlen (ptr);
}
- grub_snprintf (ptr, 5, "%x", n & 0xffff);
+ grub_snprintf (ptr, 5, "%" PRIxGRUB_UINT64_T, n & 0xffff);
return;
}
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
@@ -290,18 +438,13 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
}
return;
}
- grub_printf ("Unknown address type %d\n", target->type);
+ grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN,
+ "Unknown address type %d", target->type);
}
-/*
- Currently suppoerted adresses:
- ethernet: XX:XX:XX:XX:XX:XX
- */
-#define MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
-
-static void
-hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
+void
+grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
{
str[0] = 0;
switch (addr->type)
@@ -312,7 +455,7 @@ hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
unsigned i;
for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
{
- grub_snprintf (ptr, MAX_STR_HWADDR_LEN - (ptr - str),
+ grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
"%02x:", addr->mac[i] & 0xff);
ptr += (sizeof ("XX:") - 1);
}
@@ -380,9 +523,9 @@ static void
grub_net_network_level_interface_register (struct grub_net_network_level_interface *inter)
{
{
- char buf[MAX_STR_HWADDR_LEN];
+ char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
char name[grub_strlen (inter->name) + sizeof ("net__mac")];
- hwaddr_to_str (&inter->hwaddress, buf);
+ grub_net_hwaddr_to_str (&inter->hwaddress, buf);
grub_snprintf (name, sizeof (name), "net_%s_mac", inter->name);
grub_env_set (name, buf);
grub_register_variable_hook (name, 0, hwaddr_set_env);
@@ -408,8 +551,8 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
struct grub_net_network_level_interface *
grub_net_add_addr (const char *name,
struct grub_net_card *card,
- grub_net_network_level_address_t addr,
- grub_net_link_level_address_t hwaddress,
+ const grub_net_network_level_address_t *addr,
+ const grub_net_link_level_address_t *hwaddress,
grub_net_interface_flags_t flags)
{
struct grub_net_network_level_interface *inter;
@@ -419,8 +562,8 @@ grub_net_add_addr (const char *name,
return NULL;
inter->name = grub_strdup (name);
- grub_memcpy (&(inter->address), &addr, sizeof (inter->address));
- grub_memcpy (&(inter->hwaddress), &hwaddress, sizeof (inter->hwaddress));
+ grub_memcpy (&(inter->address), addr, sizeof (inter->address));
+ grub_memcpy (&(inter->hwaddress), hwaddress, sizeof (inter->hwaddress));
inter->flags = flags;
inter->card = card;
inter->dhcp_ack = NULL;
@@ -428,10 +571,10 @@ grub_net_add_addr (const char *name,
grub_net_network_level_interface_register (inter);
- if (addr.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+ if (addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
{
int mask = -1;
- grub_uint32_t ip_cpu = grub_be_to_cpu32 (addr.ipv4);
+ grub_uint32_t ip_cpu = grub_be_to_cpu32 (addr->ipv4);
if (!(ip_cpu & 0x80000000))
mask = 8;
else if (!(ip_cpu & 0x40000000))
@@ -498,7 +641,7 @@ grub_cmd_addaddr (struct grub_command *cmd __attribute__ ((unused)),
if (card->flags & GRUB_NET_CARD_HWADDRESS_IMMUTABLE)
flags |= GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE;
- grub_net_add_addr (args[0], card, addr, card->default_address,
+ grub_net_add_addr (args[0], card, &addr, &card->default_address,
flags);
return grub_errno;
}
@@ -685,8 +828,8 @@ grub_cmd_listcards (struct grub_command *cmd __attribute__ ((unused)),
struct grub_net_card *card;
FOR_NET_CARDS(card)
{
- char buf[MAX_STR_HWADDR_LEN];
- hwaddr_to_str (&card->default_address, buf);
+ char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
+ grub_net_hwaddr_to_str (&card->default_address, buf);
grub_printf ("%s %s\n", card->name, buf);
}
return GRUB_ERR_NONE;
@@ -700,9 +843,9 @@ grub_cmd_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
struct grub_net_network_level_interface *inf;
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
- char bufh[MAX_STR_HWADDR_LEN];
+ char bufh[GRUB_NET_MAX_STR_HWADDR_LEN];
char bufn[GRUB_NET_MAX_STR_ADDR_LEN];
- hwaddr_to_str (&inf->hwaddress, bufh);
+ grub_net_hwaddr_to_str (&inf->hwaddress, bufh);
grub_net_addr_to_str (&inf->address, bufn);
grub_printf ("%s %s %s\n", inf->name, bufh, bufn);
}
@@ -1060,13 +1203,18 @@ static void *fini_hnd;
static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
static grub_command_t cmd_lsroutes, cmd_lscards;
-static grub_command_t cmd_lsaddr;
+static grub_command_t cmd_lsaddr, cmd_slaac;
GRUB_MOD_INIT(net)
{
cmd_addaddr = grub_register_command ("net_add_addr", grub_cmd_addaddr,
"SHORTNAME CARD ADDRESS [HWADDRESS]",
N_("Add a network address."));
+ cmd_slaac = grub_register_command ("net_ipv6_autoconf",
+ grub_cmd_ipv6_autoconf,
+ "[CARD [HWADDRESS]]",
+ N_("Perform an IPV6 autoconfiguration"));
+
cmd_deladdr = grub_register_command ("net_del_addr", grub_cmd_deladdr,
"SHORTNAME",
N_("Delete a network address."));
@@ -1102,6 +1250,7 @@ GRUB_MOD_FINI(net)
grub_unregister_command (cmd_lsroutes);
grub_unregister_command (cmd_lscards);
grub_unregister_command (cmd_lsaddr);
+ grub_unregister_command (cmd_slaac);
grub_fs_unregister (&grub_net_fs);
grub_net_open = NULL;
grub_net_fini_hw (0);
diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
index b1eb3d9a8..72ee8a239 100644
--- a/grub-core/net/tcp.c
+++ b/grub-core/net/tcp.c
@@ -695,6 +695,13 @@ grub_net_recv_tcp_packet (struct grub_net_buff *nb,
grub_net_tcp_socket_t sock;
grub_err_t err;
+ /* Ignore broadcast. */
+ if (!inf)
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+
tcph = (struct tcphdr *) nb->data;
if ((grub_be_to_cpu16 (tcph->flags) >> 12) < 5)
{
diff --git a/grub-core/net/udp.c b/grub-core/net/udp.c
index e816547ac..a2315dd3f 100644
--- a/grub-core/net/udp.c
+++ b/grub-core/net/udp.c
@@ -140,6 +140,13 @@ grub_net_recv_udp_packet (struct grub_net_buff *nb,
grub_net_udp_socket_t sock;
grub_err_t err;
+ /* Ignore broadcast. */
+ if (!inf)
+ {
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+
udph = (struct udphdr *) nb->data;
if (nb->tail - nb->data < (grub_ssize_t) sizeof (*udph))
{
diff --git a/include/grub/net.h b/include/grub/net.h
index cb9d40cd0..a4785d48c 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -97,6 +97,14 @@ typedef struct grub_net_packets
#include
#endif
+struct grub_net_slaac_mac_list
+{
+ struct grub_net_slaac_mac_list *next;
+ grub_net_link_level_address_t address;
+ int slaac_counter;
+ char *name;
+};
+
struct grub_net_card
{
struct grub_net_card *next;
@@ -109,6 +117,7 @@ struct grub_net_card
unsigned idle_poll_delay_ms;
grub_uint64_t last_poll;
grub_size_t mtu;
+ struct grub_net_slaac_mac_list *slaac_list;
union
{
#ifdef GRUB_MACHINE_EFI
@@ -282,8 +291,8 @@ grub_net_session_recv (struct grub_net_session *session, void *buf,
struct grub_net_network_level_interface *
grub_net_add_addr (const char *name,
struct grub_net_card *card,
- grub_net_network_level_address_t addr,
- grub_net_link_level_address_t hwaddress,
+ const grub_net_network_level_address_t *addr,
+ const grub_net_link_level_address_t *hwaddress,
grub_net_interface_flags_t flags);
extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
@@ -404,13 +413,22 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a,
/*
Currently supported adresses:
IPv4: XXX.XXX.XXX.XXX
- IPv&: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
+ IPv6: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
*/
#define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")
+/*
+ Currently suppoerted adresses:
+ ethernet: XX:XX:XX:XX:XX:XX
+ */
+
+#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
+
void
grub_net_addr_to_str (const grub_net_network_level_address_t *target,
char *buf);
+void
+grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str);
extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
#define FOR_NET_NETWORK_LEVEL_INTERFACES(var) for (var = grub_net_network_level_interfaces; var; var = var->next)
diff --git a/include/grub/net/ethernet.h b/include/grub/net/ethernet.h
index 0749d9d87..23a935e98 100644
--- a/include/grub/net/ethernet.h
+++ b/include/grub/net/ethernet.h
@@ -36,6 +36,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
grub_net_ethertype_t ethertype);
grub_err_t
grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
- const struct grub_net_card *card);
+ struct grub_net_card *card);
#endif
diff --git a/include/grub/net/ip.h b/include/grub/net/ip.h
index 759577522..e086f4411 100644
--- a/include/grub/net/ip.h
+++ b/include/grub/net/ip.h
@@ -25,20 +25,29 @@ typedef enum grub_net_ip_protocol
{
GRUB_NET_IP_ICMP = 1,
GRUB_NET_IP_TCP = 6,
- GRUB_NET_IP_UDP = 17
+ GRUB_NET_IP_UDP = 17,
+ GRUB_NET_IP_ICMPV6 = 58
} grub_net_ip_protocol_t;
#define GRUB_NET_IP_BROADCAST 0xFFFFFFFF
+static inline grub_uint64_t
+grub_net_ipv6_get_id (const grub_net_link_level_address_t *addr)
+{
+ return grub_cpu_to_be64 (((grub_uint64_t) (addr->mac[0] ^ 2) << 56)
+ | ((grub_uint64_t) addr->mac[1] << 48)
+ | ((grub_uint64_t) addr->mac[2] << 40)
+ | 0xfffe000000ULL
+ | ((grub_uint64_t) addr->mac[3] << 16)
+ | ((grub_uint64_t) addr->mac[4] << 8)
+ | ((grub_uint64_t) addr->mac[5]));
+}
+
grub_uint16_t grub_net_ip_chksum(void *ipv, grub_size_t len);
grub_err_t
-grub_net_recv_ip4_packets (struct grub_net_buff *nb,
- const struct grub_net_card *card,
- const grub_net_link_level_address_t *hwaddress);
-grub_err_t
-grub_net_recv_ip6_packets (struct grub_net_buff *nb,
- const struct grub_net_card *card,
- const grub_net_link_level_address_t *hwaddress);
+grub_net_recv_ip_packets (struct grub_net_buff *nb,
+ struct grub_net_card *card,
+ const grub_net_link_level_address_t *hwaddress);
grub_err_t
grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
@@ -51,6 +60,12 @@ grub_net_recv_icmp_packet (struct grub_net_buff *nb,
struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *src);
grub_err_t
+grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ struct grub_net_card *card,
+ struct grub_net_network_level_interface *inf,
+ const grub_net_network_level_address_t *source,
+ const grub_net_network_level_address_t *dest);
+grub_err_t
grub_net_recv_udp_packet (struct grub_net_buff *nb,
struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *src);
@@ -65,4 +80,8 @@ grub_net_ip_transport_checksum (struct grub_net_buff *nb,
const grub_net_network_level_address_t *src,
const grub_net_network_level_address_t *dst);
+struct grub_net_network_level_interface *
+grub_net_ipv6_get_link_local (struct grub_net_card *card,
+ const grub_net_link_level_address_t *hwaddr);
+
#endif