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

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