Blame SOURCES/0162-efinet-skip-virtual-IPv4-and-IPv6-devices-when-enume.patch

f731ee
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
f731ee
From: Andrei Borzenkov <arvidjaar@gmail.com>
f731ee
Date: Thu, 7 May 2015 20:37:17 +0300
f731ee
Subject: [PATCH] efinet: skip virtual IPv4 and IPv6 devices when enumerating
f731ee
 cards
f731ee
f731ee
EDK2 PXE driver creates two child devices - IPv4 and IPv6 - with
f731ee
bound SNP instance. This means we get three cards for every physical
f731ee
adapter when enumerating. Not only is this confusing, this may result
f731ee
in grub ignoring packets that come in via the "wrong" card.
f731ee
f731ee
Example of device hierarchy is
f731ee
f731ee
 Ctrl[91] PciRoot(0x0)/Pci(0x3,0x0)
f731ee
   Ctrl[95] PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)
f731ee
     Ctrl[B4] PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
f731ee
     Ctrl[BC] PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000)
f731ee
f731ee
Skip PXE created virtual devices when enumerating cards. Make sure to
f731ee
find real card when applying initial autoconfiguration during PXE boot,
f731ee
this information is associated with one of child devices.
f731ee
---
f731ee
 grub-core/net/drivers/efi/efinet.c | 51 +++++++++++++++++++++++++++++++++++++-
f731ee
 1 file changed, 50 insertions(+), 1 deletion(-)
f731ee
f731ee
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
f731ee
index 78df215be12..caa7b50228b 100644
f731ee
--- a/grub-core/net/drivers/efi/efinet.c
f731ee
+++ b/grub-core/net/drivers/efi/efinet.c
f731ee
@@ -174,6 +174,29 @@ grub_efinet_findcards (void)
f731ee
     {
f731ee
       grub_efi_simple_network_t *net;
f731ee
       struct grub_net_card *card;
f731ee
+      grub_efi_device_path_t *dp, *parent = NULL, *child = NULL;
f731ee
+
f731ee
+      /* EDK2 UEFI PXE driver creates IPv4 and IPv6 messaging devices as
f731ee
+	 children of main MAC messaging device. We only need one device with
f731ee
+	 bound SNP per physical card, otherwise they compete with each other
f731ee
+	 when polling for incoming packets.
f731ee
+       */
f731ee
+      dp = grub_efi_get_device_path (*handle);
f731ee
+      if (!dp)
f731ee
+	continue;
f731ee
+      for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp); dp = GRUB_EFI_NEXT_DEVICE_PATH (dp))
f731ee
+	{
f731ee
+	  parent = child;
f731ee
+	  child = dp;
f731ee
+	}
f731ee
+      if (child
f731ee
+	  && GRUB_EFI_DEVICE_PATH_TYPE (child) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
f731ee
+	  && (GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
f731ee
+	      || GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
f731ee
+	  && parent
f731ee
+	  && GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
f731ee
+	  && GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
f731ee
+	continue;
f731ee
 
f731ee
       net = grub_efi_open_protocol (*handle, &net_io_guid,
f731ee
 				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
f731ee
@@ -252,7 +275,33 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
f731ee
     if (! cdp)
f731ee
       continue;
f731ee
     if (grub_efi_compare_device_paths (dp, cdp) != 0)
f731ee
-      continue;
f731ee
+      {
f731ee
+	grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
f731ee
+	int match;
f731ee
+
f731ee
+	/* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
f731ee
+	   as children of Ethernet card and binds PXE and Load File protocols
f731ee
+	   to it. Loaded Image Device Path protocol will point to these pseudo
f731ee
+	   devices. We skip them when enumerating cards, so here we need to
f731ee
+	   find matching MAC device.
f731ee
+         */
f731ee
+	ldp = grub_efi_find_last_device_path (dp);
f731ee
+	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
f731ee
+	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
f731ee
+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
f731ee
+	  continue;
f731ee
+	dup_dp = grub_efi_duplicate_device_path (dp);
f731ee
+	if (!dup_dp)
f731ee
+	  continue;
f731ee
+	dup_ldp = grub_efi_find_last_device_path (dup_dp);
f731ee
+	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
f731ee
+	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
f731ee
+	dup_ldp->length = sizeof (*dup_ldp);
f731ee
+	match = grub_efi_compare_device_paths (dup_dp, cdp) == 0;
f731ee
+	grub_free (dup_dp);
f731ee
+	if (!match)
f731ee
+	  continue;
f731ee
+      }
f731ee
     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
f731ee
 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
f731ee
     if (! pxe)