We have some hardware that doesn't honor EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST properly so we aren't getting RA's that are multicasted properly (our switches respond to solicitations with a multicast rather than a unicast). I don't want to add this filtering by default, so add a new command to allow a user to specify a multicast receive filter. We use it like this
efinet_multicast_filter efinet0 33:33:0:0:0:1 to get ipv6 multicasts which allows us to receive the router advertisements. Thanks, Signed-off-by: Josef Bacik <jba...@fb.com> --- grub-core/kern/efi/efi.c | 12 ++++----- grub-core/net/drivers/efi/efinet.c | 51 ++++++++++++++++++++++++++++++++++++++ grub-core/net/net.c | 43 ++++++++++++++++++++++++++++++++ include/grub/efi/api.h | 5 +++- include/grub/net.h | 3 +++ 5 files changed, 107 insertions(+), 7 deletions(-) diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index 2e77834..efc3d33 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -652,12 +652,12 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) dp; grub_printf ("/MacAddr(%02x:%02x:%02x:%02x:%02x:%02x,%x)", - (unsigned) mac->mac_address[0], - (unsigned) mac->mac_address[1], - (unsigned) mac->mac_address[2], - (unsigned) mac->mac_address[3], - (unsigned) mac->mac_address[4], - (unsigned) mac->mac_address[5], + (unsigned) mac->mac_address.addr[0], + (unsigned) mac->mac_address.addr[1], + (unsigned) mac->mac_address.addr[2], + (unsigned) mac->mac_address.addr[3], + (unsigned) mac->mac_address.addr[4], + (unsigned) mac->mac_address.addr[5], (unsigned) mac->if_type); } break; diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c index c8f80a1..8c2c4f8 100644 --- a/grub-core/net/drivers/efi/efinet.c +++ b/grub-core/net/drivers/efi/efinet.c @@ -23,6 +23,7 @@ #include <grub/efi/api.h> #include <grub/efi/efi.h> #include <grub/i18n.h> +#include <grub/command.h> GRUB_MOD_LICENSE ("GPLv3+"); @@ -451,9 +452,58 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, } } +static grub_err_t +grub_cmd_multicast_filter (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_card *card; + grub_efi_simple_network_t *net; + grub_net_link_level_address_t hwaddr; + grub_efi_mac_address_t filter_mac[1]; + grub_efi_status_t st; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected")); + + FOR_NET_CARDS (card) + if (grub_strcmp (card->name, args[0]) == 0) + break; + + if (card == NULL) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); + if (card->driver != &efidriver) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not an efi card")); + + if (grub_net_str_to_hwaddr (args[1], &hwaddr) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("couldn't parse hw address")); + grub_memset (filter_mac, 0, sizeof(filter_mac)); + grub_memcpy (filter_mac, hwaddr.mac, 6); + + net = card->efi_net; + if (!(net->mode->receive_filter_mask & + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) + return grub_error (GRUB_ERR_IO, + N_("device doesn't support multicast filtering")); + + st = efi_call_6 (net->receive_filters, net, + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST, 0, 0, 1, + filter_mac); + if (st != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_IO, + N_("could not set multicast filter address")); + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_multicast_filter; + GRUB_MOD_INIT(efinet) { grub_efinet_findcards (); + cmd_multicast_filter = grub_register_command ("efinet_multicast_filter", + grub_cmd_multicast_filter, + N_("CARD HWADDRESS"), + N_("Add a multicast filter")); grub_efi_net_config = grub_efi_net_config_real; } @@ -464,5 +514,6 @@ GRUB_MOD_FINI(efinet) FOR_NET_CARDS_SAFE (card, next) if (card->driver == &efidriver) grub_net_card_unregister (card); + grub_unregister_command(cmd_multicast_filter); } diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 65bea28..3a69f63 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -480,6 +480,49 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) return 1; } +int +grub_net_str_to_hwaddr (const char *val, grub_net_link_level_address_t *hwaddr) +{ + grub_uint8_t newmac[6]; + const char *ptr = val; + int word; + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; + if (ptr[0] == ':') + ptr++; + + for (word = 0; word < 6; word++) + { + unsigned long t; + if (*ptr == ':') + { + word--; + ptr++; + continue; + } + t = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; + break; + } + if (t & ~0xff) + return 0; + newmac[word] = t; + if (*ptr != ':') + break; + ptr++; + } + if (*ptr != 0) + return grub_error (GRUB_ERR_NET_BAD_ADDRESS, + N_("unrecognized link level address '%s'"), + val); + hwaddr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (hwaddr->mac, newmac, 6); + return 1; +} + static int match_net (const grub_net_network_level_netaddress_t *net, const grub_net_network_level_address_t *addr) diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 9a73976..48940be 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -523,7 +523,10 @@ typedef void *grub_efi_handle_t; typedef void *grub_efi_event_t; typedef grub_efi_uint64_t grub_efi_lba_t; typedef grub_efi_uintn_t grub_efi_tpl_t; -typedef grub_uint8_t grub_efi_mac_address_t[32]; +typedef struct { + grub_uint8_t addr[32]; +} grub_efi_mac_address_t; + typedef grub_uint8_t grub_efi_ipv4_address_t[4]; typedef grub_uint16_t grub_efi_ipv6_address_t[8]; typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); diff --git a/include/grub/net.h b/include/grub/net.h index a1ff519..12cc1db 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -522,6 +522,9 @@ 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); +int +grub_net_str_to_hwaddr (const char *val, + grub_net_link_level_address_t *hwaddr); grub_err_t grub_env_set_net_property (const char *intername, const char *suffix, -- 1.8.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel