nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

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

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