Blame SOURCES/0164-efinet-enable-hardware-filters-when-opening-interfac.patch

28f7f8
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
ecb9bb
From: Andrei Borzenkov <arvidjaar@gmail.com>
ecb9bb
Date: Tue, 16 Jun 2015 19:52:45 +0300
28f7f8
Subject: [PATCH] efinet: enable hardware filters when opening interface
ecb9bb
ecb9bb
Exclusive open on SNP will close all existing protocol instances which
ecb9bb
may disable all receive filters on interface. Reinstall them after we
ecb9bb
opened protocol exclusively.
ecb9bb
ecb9bb
Also follow UEFI specification recommendation and stop interfaces when
ecb9bb
closing them:
ecb9bb
ecb9bb
Unexpected system errors, reboots and hangs can occur if an OS is loaded
ecb9bb
and the network devices are not Shutdown() and Stopped().
ecb9bb
ecb9bb
Also by: Mark Salter <msalter@redhat.com>
ecb9bb
Closes: 45204
ecb9bb
---
ecb9bb
 grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++++
ecb9bb
 include/grub/efi/api.h             | 20 +++++++++++++++++---
ecb9bb
 2 files changed, 42 insertions(+), 3 deletions(-)
ecb9bb
ecb9bb
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
28f7f8
index 6a1dd1f9dff..7b8c4a59d10 100644
ecb9bb
--- a/grub-core/net/drivers/efi/efinet.c
ecb9bb
+++ b/grub-core/net/drivers/efi/efinet.c
ecb9bb
@@ -168,6 +168,29 @@ open_card (struct grub_net_card *dev)
ecb9bb
 	return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed",
ecb9bb
 			   dev->name);
ecb9bb
 
ecb9bb
+      /* Enable hardware receive filters if driver declares support for it.
ecb9bb
+	 We need unicast and broadcast and additionaly all nodes and
ecb9bb
+	 solicited multicast for IPv6. Solicited multicast is per-IPv6
ecb9bb
+	 address and we currently do not have API to do it so simply
ecb9bb
+	 try to enable receive of all multicast packets or evertyhing in
ecb9bb
+	 the worst case (i386 PXE driver always enables promiscuous too).
ecb9bb
+
ecb9bb
+	 This does trust firmware to do what it claims to do.
ecb9bb
+       */
ecb9bb
+      if (net->mode->receive_filter_mask)
ecb9bb
+	{
ecb9bb
+	  grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST   |
ecb9bb
+				  GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
ecb9bb
+				  GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
ecb9bb
+
ecb9bb
+	  filters &= net->mode->receive_filter_mask;
ecb9bb
+	  if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST))
ecb9bb
+	    filters |= (net->mode->receive_filter_mask &
ecb9bb
+			GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS);
ecb9bb
+
ecb9bb
+	  efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL);
ecb9bb
+	}
ecb9bb
+
ecb9bb
       efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
ecb9bb
 		  dev->efi_net, &net_io_guid,
ecb9bb
 		  grub_efi_image_handle, dev->efi_handle);
ecb9bb
@@ -181,6 +204,8 @@ open_card (struct grub_net_card *dev)
ecb9bb
 static void
ecb9bb
 close_card (struct grub_net_card *dev)
ecb9bb
 {
ecb9bb
+  efi_call_1 (dev->efi_net->shutdown, dev->efi_net);
ecb9bb
+  efi_call_1 (dev->efi_net->stop, dev->efi_net);
ecb9bb
   efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
ecb9bb
 	      dev->efi_net, &net_io_guid,
ecb9bb
 	      grub_efi_image_handle, dev->efi_handle);
ecb9bb
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
28f7f8
index 142340372e1..029ee92f5d0 100644
ecb9bb
--- a/include/grub/efi/api.h
ecb9bb
+++ b/include/grub/efi/api.h
ecb9bb
@@ -1564,17 +1564,31 @@ enum
ecb9bb
     GRUB_EFI_NETWORK_INITIALIZED,
ecb9bb
   };
ecb9bb
 
ecb9bb
+enum
ecb9bb
+  {
ecb9bb
+    GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST		  = 0x01,
ecb9bb
+    GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST		  = 0x02,
ecb9bb
+    GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST		  = 0x04,
ecb9bb
+    GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS		  = 0x08,
ecb9bb
+    GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST = 0x10,
ecb9bb
+  };
ecb9bb
+
ecb9bb
 struct grub_efi_simple_network
ecb9bb
 {
ecb9bb
   grub_uint64_t revision;
ecb9bb
   grub_efi_status_t (*start) (struct grub_efi_simple_network *this);
ecb9bb
-  void (*stop) (void);
ecb9bb
+  grub_efi_status_t (*stop) (struct grub_efi_simple_network *this);
ecb9bb
   grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this,
ecb9bb
 				   grub_efi_uintn_t extra_rx,
ecb9bb
 				   grub_efi_uintn_t extra_tx);
ecb9bb
   void (*reset) (void);
ecb9bb
-  void (*shutdown) (void);
ecb9bb
-  void (*receive_filters) (void);
ecb9bb
+  grub_efi_status_t (*shutdown) (struct grub_efi_simple_network *this);
ecb9bb
+  grub_efi_status_t (*receive_filters) (struct grub_efi_simple_network *this,
ecb9bb
+					grub_uint32_t enable,
ecb9bb
+					grub_uint32_t disable,
ecb9bb
+					grub_efi_boolean_t reset_mcast_filter,
ecb9bb
+					grub_efi_uintn_t mcast_filter_count,
ecb9bb
+					grub_efi_mac_address_t *mcast_filter);
ecb9bb
   void (*station_address) (void);
ecb9bb
   void (*statistics) (void);
ecb9bb
   void (*mcastiptomac) (void);