]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
some more ipv6 code
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 12 Oct 2011 08:20:55 +0000 (10:20 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 12 Oct 2011 08:20:55 +0000 (10:20 +0200)
12 files changed:
grub-core/Makefile.core.def
grub-core/net/bootp.c
grub-core/net/ethernet.c
grub-core/net/icmp.c
grub-core/net/icmp6.c [new file with mode: 0644]
grub-core/net/ip.c
grub-core/net/net.c
grub-core/net/tcp.c
grub-core/net/udp.c
include/grub/net.h
include/grub/net/ethernet.h
include/grub/net/ip.h

index aa5f2bfe74b026cab3ab6c6512942bae95895762..3827227b8c16484baba5a1279ecb1a76aadb1411 100644 (file)
@@ -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;
index 3187f2e9c22ce07539194c534c8221cda235c625..1b852725539d90071532a13aa55f6f96621c477a 100644 (file)
@@ -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)
index 053f87b56cca965ff29b9e71c6d6a020c07b94e9..8d7f6683031e7b985dbf917fd1606a8962bfb033 100644 (file)
@@ -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;
index 8ea0201071c88efc71b05c7881277cabbfe16374..88132b142e3c86ebdaa4e394bd357f5d2fa6cf00 100644 (file)
@@ -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 (file)
index 0000000..ac12c57
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/net.h>
+#include <grub/net/ip.h>
+#include <grub/net/netbuff.h>
+
+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;
+}
index 32a7d7fe76d6ba4a7d310cf85f21d47c40d1005a..18593da4947f64d16a90f3f4405128e809358753 100644 (file)
@@ -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;
+}
index 398e6f5aec308001a9353e66acb5ddd97b1fe8f0..1c6d47757d700b7bdeff6ad918257df1227814ee 100644 (file)
@@ -27,6 +27,7 @@
 #include <grub/command.h>
 #include <grub/env.h>
 #include <grub/net/ethernet.h>
+#include <grub/net/ip.h>
 #include <grub/loader.h>
 #include <grub/bufio.h>
 #include <grub/kernel.h>
@@ -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);
index b1eb3d9a8e6ad012a8d9eb5dd8849ac7ea8b3798..72ee8a239d2f8c0bcc8e3ac910d15ba42a6e8fc9 100644 (file)
@@ -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)
     {
index e816547ac045775561a702210b201963e9241347..a2315dd3fb64a475e13d433a654cc2de5e653f81 100644 (file)
@@ -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))
     {
index cb9d40cd07772cd6a505db17888a733523402a15..a4785d48c02cb6d4199809f5ab88805200a0a7fb 100644 (file)
@@ -97,6 +97,14 @@ typedef struct grub_net_packets
 #include <grub/efi/api.h>
 #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)
index 0749d9d87c4414a4d000c16923f779afbeeb2bb0..23a935e98d97dddaa109009ad542646b8b3a4b02 100644 (file)
@@ -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 
index 759577522f53e81035409d46d5e1456113157b13..e086f4411f38277707a986ac4cab32c83b0aa198 100644 (file)
@@ -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