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

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