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