diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 4fdeac3ef..a088244b4 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -82,7 +82,7 @@ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask) grub_memcpy (&gw.ipv4, ptr, sizeof (gw.ipv4)); rname = grub_xasprintf ("%s:default", name); if (rname) - grub_net_add_route_gw (rname, target, gw); + grub_net_add_route_gw (rname, target, gw, NULL); grub_free (rname); } break; diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c index eff9085ed..6bd3b922e 100644 --- a/grub-core/net/drivers/ieee1275/ofnet.c +++ b/grub-core/net/drivers/ieee1275/ofnet.c @@ -151,7 +151,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, grub_net_network_level_address_t client_addr, gateway_addr, subnet_mask; grub_net_link_level_address_t hw_addr; grub_net_interface_flags_t flags = 0; - struct grub_net_network_level_interface *inter; + struct grub_net_network_level_interface *inter = NULL; hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; @@ -221,7 +221,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, target.ipv4.masksize = 0; rname = grub_xasprintf ("%s:default", ((*card)->name)); if (rname) - grub_net_add_route_gw (rname, target, gateway_addr); + grub_net_add_route_gw (rname, target, gateway_addr, inter); else return grub_errno; } diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c index 7953e68ec..2cbd95dce 100644 --- a/grub-core/net/icmp6.c +++ b/grub-core/net/icmp6.c @@ -115,6 +115,7 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, grub_uint8_t ttl) { struct icmp_header *icmph; + struct grub_net_network_level_interface *orig_inf = inf; grub_err_t err; grub_uint16_t checksum; @@ -345,14 +346,31 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, { grub_uint8_t *ptr; struct option_header *ohdr; + struct router_adv *radv; + struct grub_net_network_level_interface *route_inf = NULL; + int default_route = 0; if (icmph->code) break; + radv = (struct router_adv *)nb->data; err = grub_netbuff_pull (nb, sizeof (struct router_adv)); if (err) { grub_netbuff_free (nb); return err; } + if (grub_be_to_cpu16 (radv->router_lifetime) > 0) + { + struct grub_net_route *route; + + FOR_NET_ROUTES (route) + { + if (!grub_memcmp (&route->gw, source, sizeof (route->gw))) + break; + } + if (route == NULL) + default_route = 1; + } + for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail; ptr += ohdr->len * 8) { @@ -413,7 +431,11 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, /* Update lease time if needed here once we have lease times. */ if (inf) - continue; + { + if (!route_inf) + route_inf = inf; + continue; + } grub_dprintf ("net", "creating slaac\n"); @@ -429,12 +451,51 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, inf = grub_net_add_addr (name, card, &addr, &slaac->address, 0); + if (!route_inf) + route_inf = inf; grub_net_add_route (name, netaddr, inf); grub_free (name); } } } } + if (default_route) + { + char *name; + grub_net_network_level_netaddress_t netaddr; + name = grub_xasprintf ("%s:ra:default6", card->name); + if (!name) + { + grub_errno = GRUB_ERR_NONE; + goto next; + } + /* Default routes take alll of the traffic, so make the mask huge */ + netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + netaddr.ipv6.masksize = 0; + netaddr.ipv6.base[0] = 0; + netaddr.ipv6.base[1] = 0; + + /* May not have gotten slaac info, find a global address on this + card. */ + if (route_inf == NULL) + { + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + if (inf->card == card && inf != orig_inf + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && grub_net_hwaddr_cmp(&inf->hwaddress, + &orig_inf->hwaddress) == 0) + { + route_inf = inf; + break; + } + } + } + if (route_inf != NULL) + grub_net_add_route_gw (name, netaddr, *source, route_inf); + grub_free (name); + } +next: if (ptr != nb->tail) break; } diff --git a/grub-core/net/net.c b/grub-core/net/net.c index d07029b34..942459527 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -37,21 +37,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); char *grub_net_default_server; -struct grub_net_route -{ - struct grub_net_route *next; - struct grub_net_route **prev; - grub_net_network_level_netaddress_t target; - char *name; - struct grub_net_network_level_protocol *prot; - int is_gateway; - union - { - struct grub_net_network_level_interface *interface; - grub_net_network_level_address_t gw; - }; -}; - struct grub_net_route *grub_net_routes = NULL; struct grub_net_network_level_interface *grub_net_network_level_interfaces = NULL; struct grub_net_card *grub_net_cards = NULL; @@ -410,14 +395,6 @@ grub_cmd_ipv6_autoconf (struct grub_command *cmd __attribute__ ((unused)), return err; } -static inline void -grub_net_route_register (struct grub_net_route *route) -{ - grub_list_push (GRUB_AS_LIST_P (&grub_net_routes), - GRUB_AS_LIST (route)); -} - -#define FOR_NET_ROUTES(var) for (var = grub_net_routes; var; var = var->next) static int parse_ip (const char *val, grub_uint32_t *ip, const char **rest) @@ -524,6 +501,8 @@ match_net (const grub_net_network_level_netaddress_t *net, case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: { grub_uint64_t mask[2]; + if (net->ipv6.masksize == 0) + return 1; if (net->ipv6.masksize <= 64) { mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize); @@ -687,7 +666,14 @@ grub_net_route_address (grub_net_network_level_address_t addr, return GRUB_ERR_NONE; } if (depth == 0) - *gateway = bestroute->gw; + { + *gateway = bestroute->gw; + if (bestroute->interface != NULL) + { + *interf = bestroute->interface; + return GRUB_ERR_NONE; + } + } curtarget = bestroute->gw; } @@ -1109,7 +1095,8 @@ grub_net_add_route (const char *name, grub_err_t grub_net_add_route_gw (const char *name, grub_net_network_level_netaddress_t target, - grub_net_network_level_address_t gw) + grub_net_network_level_address_t gw, + struct grub_net_network_level_interface *inter) { struct grub_net_route *route; @@ -1127,6 +1114,7 @@ grub_net_add_route_gw (const char *name, route->target = target; route->is_gateway = 1; route->gw = gw; + route->interface = inter; grub_net_route_register (route); @@ -1152,7 +1140,7 @@ grub_cmd_addroute (struct grub_command *cmd __attribute__ ((unused)), err = grub_net_resolve_address (args[3], &gw); if (err) return err; - return grub_net_add_route_gw (args[0], target, gw); + return grub_net_add_route_gw (args[0], target, gw, NULL); } else { diff --git a/include/grub/net.h b/include/grub/net.h index 538baa33e..2192fa186 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -191,6 +191,18 @@ typedef struct grub_net_network_level_netaddress }; } grub_net_network_level_netaddress_t; +struct grub_net_route +{ + struct grub_net_route *next; + struct grub_net_route **prev; + grub_net_network_level_netaddress_t target; + char *name; + struct grub_net_network_level_protocol *prot; + int is_gateway; + struct grub_net_network_level_interface *interface; + grub_net_network_level_address_t gw; +}; + #define FOR_PACKETS(cont,var) for (var = (cont).first; var; var = var->next) static inline grub_err_t @@ -367,6 +379,16 @@ grub_net_card_unregister (struct grub_net_card *card); #define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0)) +extern struct grub_net_route *grub_net_routes; + +static inline void +grub_net_route_register (struct grub_net_route *route) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_net_routes), + GRUB_AS_LIST (route)); +} + +#define FOR_NET_ROUTES(var) for (var = grub_net_routes; var; var = var->next) struct grub_net_session * grub_net_open_tcp (char *address, grub_uint16_t port); @@ -392,7 +414,8 @@ grub_net_add_route (const char *name, grub_err_t grub_net_add_route_gw (const char *name, grub_net_network_level_netaddress_t target, - grub_net_network_level_address_t gw); + grub_net_network_level_address_t gw, + struct grub_net_network_level_interface *inter); #define GRUB_NET_BOOTP_MAC_ADDR_LEN 16