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

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