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