All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] efinet: add efinet_multicast_filter command
@ 2015-11-05 19:23 Josef Bacik
  2015-11-05 20:28 ` Vladimir 'phcoder' Serbinenko
  2015-11-06  4:15 ` Andrei Borzenkov
  0 siblings, 2 replies; 10+ messages in thread
From: Josef Bacik @ 2015-11-05 19:23 UTC (permalink / raw)
  To: grub-devel, kernel-team; +Cc: Josef Bacik

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 <jbacik@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



^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-11-10 18:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-05 19:23 [PATCH] efinet: add efinet_multicast_filter command Josef Bacik
2015-11-05 20:28 ` Vladimir 'phcoder' Serbinenko
2015-11-05 21:17   ` Josef Bacik
2015-11-05 23:47     ` Vladimir 'phcoder' Serbinenko
2015-11-06 18:42       ` Andrei Borzenkov
2015-11-06 18:47         ` Vladimir 'phcoder' Serbinenko
2015-11-07  6:08           ` Andrei Borzenkov
2015-11-10 18:33   ` Josef Bacik
2015-11-06  4:15 ` Andrei Borzenkov
2015-11-06 14:12   ` Josef Bacik

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.