|
|
ecb9bb |
From 46d5b1ccce248a275b1dcf15824fb3501a32d9dc Mon Sep 17 00:00:00 2001
|
|
|
ecb9bb |
From: Peter Jones <pjones@redhat.com>
|
|
|
ecb9bb |
Date: Fri, 11 Sep 2015 17:30:49 -0400
|
|
|
ecb9bb |
Subject: [PATCH] Be more aggro about actually using the *configured* network
|
|
|
ecb9bb |
device.
|
|
|
ecb9bb |
|
|
|
ecb9bb |
Right now we use any SNP device with the same mac+IP block, but when
|
|
|
ecb9bb |
it's discovered there will be more than one of them. We need to pick
|
|
|
ecb9bb |
the same one we were loaded with, so that it'll be configured the same
|
|
|
ecb9bb |
way as it was before, and won't be re-used by the system firmware later.
|
|
|
ecb9bb |
|
|
|
ecb9bb |
Resolves: rhbz#1257475
|
|
|
ecb9bb |
|
|
|
ecb9bb |
Signed-off-by: Peter Jones <example@example.com>
|
|
|
ecb9bb |
---
|
|
|
ecb9bb |
grub-core/net/drivers/efi/efinet.c | 124 +++++++++++++++++++++++++++++--------
|
|
|
ecb9bb |
include/grub/efi/api.h | 4 ++
|
|
|
ecb9bb |
2 files changed, 102 insertions(+), 26 deletions(-)
|
|
|
ecb9bb |
|
|
|
ecb9bb |
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
|
|
|
ecb9bb |
index c3a128c..fd47b8a 100644
|
|
|
ecb9bb |
--- a/grub-core/net/drivers/efi/efinet.c
|
|
|
ecb9bb |
+++ b/grub-core/net/drivers/efi/efinet.c
|
|
|
ecb9bb |
@@ -239,46 +239,85 @@ grub_efinet_get_device_handle (struct grub_net_card *card)
|
|
|
ecb9bb |
return card->efi_handle;
|
|
|
ecb9bb |
}
|
|
|
ecb9bb |
|
|
|
ecb9bb |
-static void
|
|
|
ecb9bb |
-grub_efinet_findcards (void)
|
|
|
ecb9bb |
+static int
|
|
|
ecb9bb |
+grub_efinet_find_snp_cards (int preferred_only, grub_efi_handle_t preferred,
|
|
|
ecb9bb |
+ int *i)
|
|
|
ecb9bb |
{
|
|
|
ecb9bb |
- grub_efi_uintn_t num_handles;
|
|
|
ecb9bb |
- grub_efi_handle_t *handles;
|
|
|
ecb9bb |
+ grub_efi_uintn_t num_handles = 0;
|
|
|
ecb9bb |
+ grub_efi_handle_t *handles = NULL;
|
|
|
ecb9bb |
grub_efi_handle_t *handle;
|
|
|
ecb9bb |
- int i = 0;
|
|
|
ecb9bb |
+ grub_efi_device_path_t *pdp = NULL, *pp = NULL, *pc = NULL;
|
|
|
ecb9bb |
+ int ret = 0;
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ if (preferred)
|
|
|
ecb9bb |
+ {
|
|
|
ecb9bb |
+ grub_efi_device_path_t *pdpc;
|
|
|
ecb9bb |
+ pdpc = pdp = grub_efi_get_device_path (preferred);
|
|
|
ecb9bb |
+ if (pdp == NULL)
|
|
|
ecb9bb |
+ {
|
|
|
ecb9bb |
+ grub_print_error ();
|
|
|
ecb9bb |
+ return -1;
|
|
|
ecb9bb |
+ }
|
|
|
ecb9bb |
|
|
|
ecb9bb |
- /* Find handles which support the disk io interface. */
|
|
|
ecb9bb |
+ for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (pdpc);
|
|
|
ecb9bb |
+ pdpc = GRUB_EFI_NEXT_DEVICE_PATH (pdpc))
|
|
|
ecb9bb |
+ {
|
|
|
ecb9bb |
+ pp = pc;
|
|
|
ecb9bb |
+ pc = pdpc;
|
|
|
ecb9bb |
+ }
|
|
|
ecb9bb |
+ }
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ /* Find handles which support the SNP interface. */
|
|
|
ecb9bb |
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid,
|
|
|
ecb9bb |
0, &num_handles);
|
|
|
ecb9bb |
- if (! handles)
|
|
|
ecb9bb |
- return;
|
|
|
ecb9bb |
- for (handle = handles; num_handles--; handle++)
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ for (handle = handles; handle && num_handles--; handle++)
|
|
|
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 |
+ /* if we're looking for only the preferred handle, skip anything that
|
|
|
ecb9bb |
+ isn't it. */
|
|
|
ecb9bb |
+ if (preferred_only && preferred != NULL && *handle != preferred)
|
|
|
ecb9bb |
+ continue;
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ /* if we're not looking for the preferred handle, skip it if it's
|
|
|
ecb9bb |
+ found. */
|
|
|
ecb9bb |
+ if (!preferred_only && *handle == preferred)
|
|
|
ecb9bb |
+ continue;
|
|
|
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 |
+ for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp);
|
|
|
ecb9bb |
+ 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 |
+ if (!preferred_only)
|
|
|
ecb9bb |
+ {
|
|
|
ecb9bb |
+ if (pp && pc
|
|
|
ecb9bb |
+ && grub_efi_compare_device_paths (pp, parent) == 0
|
|
|
ecb9bb |
+ && grub_efi_compare_device_paths (pc, child) == 0)
|
|
|
ecb9bb |
+ continue;
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ if (child
|
|
|
ecb9bb |
+ && (GRUB_EFI_DEVICE_PATH_IS_TYPE(child,
|
|
|
ecb9bb |
+ GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE,
|
|
|
ecb9bb |
+ GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ||
|
|
|
ecb9bb |
+ GRUB_EFI_DEVICE_PATH_IS_TYPE(child,
|
|
|
ecb9bb |
+ GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE,
|
|
|
ecb9bb |
+ GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE))
|
|
|
ecb9bb |
+ && parent
|
|
|
ecb9bb |
+ && (GRUB_EFI_DEVICE_PATH_IS_TYPE(parent,
|
|
|
ecb9bb |
+ GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE,
|
|
|
ecb9bb |
+ GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)))
|
|
|
ecb9bb |
+ continue;
|
|
|
ecb9bb |
+ }
|
|
|
ecb9bb |
|
|
|
ecb9bb |
net = grub_efi_open_protocol (*handle, &net_io_guid,
|
|
|
ecb9bb |
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
|
ecb9bb |
@@ -302,7 +341,7 @@ grub_efinet_findcards (void)
|
|
|
ecb9bb |
{
|
|
|
ecb9bb |
grub_print_error ();
|
|
|
ecb9bb |
grub_free (handles);
|
|
|
ecb9bb |
- return;
|
|
|
ecb9bb |
+ return -1;
|
|
|
ecb9bb |
}
|
|
|
ecb9bb |
|
|
|
ecb9bb |
card->mtu = net->mode->max_packet_size;
|
|
|
ecb9bb |
@@ -313,13 +352,14 @@ grub_efinet_findcards (void)
|
|
|
ecb9bb |
grub_print_error ();
|
|
|
ecb9bb |
grub_free (handles);
|
|
|
ecb9bb |
grub_free (card);
|
|
|
ecb9bb |
- return;
|
|
|
ecb9bb |
+ return -1;
|
|
|
ecb9bb |
}
|
|
|
ecb9bb |
card->txbusy = 0;
|
|
|
ecb9bb |
|
|
|
ecb9bb |
card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
|
|
|
ecb9bb |
|
|
|
ecb9bb |
- card->name = grub_xasprintf ("efinet%d", i++);
|
|
|
ecb9bb |
+ card->name = grub_xasprintf ("efinet%d", *i);
|
|
|
ecb9bb |
+ *i = (*i)+1;
|
|
|
ecb9bb |
card->driver = &efidriver;
|
|
|
ecb9bb |
card->flags = 0;
|
|
|
ecb9bb |
card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
|
|
ecb9bb |
@@ -330,8 +370,38 @@ grub_efinet_findcards (void)
|
|
|
ecb9bb |
card->efi_handle = *handle;
|
|
|
ecb9bb |
|
|
|
ecb9bb |
grub_net_card_register (card);
|
|
|
ecb9bb |
+ ret++;
|
|
|
ecb9bb |
}
|
|
|
ecb9bb |
grub_free (handles);
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ return ret;
|
|
|
ecb9bb |
+}
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+static void
|
|
|
ecb9bb |
+grub_efinet_findcards (void)
|
|
|
ecb9bb |
+{
|
|
|
ecb9bb |
+ grub_efi_loaded_image_t *image = NULL;
|
|
|
ecb9bb |
+ int rc;
|
|
|
ecb9bb |
+ int efinet_number = 0;
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ image = grub_efi_get_loaded_image (grub_efi_image_handle);
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ if (image && image->device_handle)
|
|
|
ecb9bb |
+ {
|
|
|
ecb9bb |
+ rc = grub_efinet_find_snp_cards (1, image->device_handle, &efinet_number);
|
|
|
ecb9bb |
+ if (rc < 0)
|
|
|
ecb9bb |
+ return;
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
+ rc = grub_efinet_find_snp_cards (0, image->device_handle, &efinet_number);
|
|
|
ecb9bb |
+ if (rc < 0)
|
|
|
ecb9bb |
+ return;
|
|
|
ecb9bb |
+ }
|
|
|
ecb9bb |
+ else
|
|
|
ecb9bb |
+ {
|
|
|
ecb9bb |
+ rc = grub_efinet_find_snp_cards (0, NULL, &efinet_number);
|
|
|
ecb9bb |
+ if (rc < 0)
|
|
|
ecb9bb |
+ return;
|
|
|
ecb9bb |
+ }
|
|
|
ecb9bb |
}
|
|
|
ecb9bb |
|
|
|
ecb9bb |
static void
|
|
|
ecb9bb |
@@ -353,6 +423,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
|
|
|
ecb9bb |
struct grub_efi_pxe_mode *pxe_mode;
|
|
|
ecb9bb |
if (card->driver != &efidriver)
|
|
|
ecb9bb |
continue;
|
|
|
ecb9bb |
+ if (hnd != card->efi_handle)
|
|
|
ecb9bb |
+ continue;
|
|
|
ecb9bb |
cdp = grub_efi_get_device_path (card->efi_handle);
|
|
|
ecb9bb |
if (! cdp)
|
|
|
ecb9bb |
continue;
|
|
|
ecb9bb |
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
|
|
|
ecb9bb |
index 029ee92..f0640c2 100644
|
|
|
ecb9bb |
--- a/include/grub/efi/api.h
|
|
|
ecb9bb |
+++ b/include/grub/efi/api.h
|
|
|
ecb9bb |
@@ -573,6 +573,10 @@ typedef struct grub_efi_device_path grub_efi_device_path_t;
|
|
|
ecb9bb |
It seems to be identical to EFI_DEVICE_PATH. */
|
|
|
ecb9bb |
typedef struct grub_efi_device_path grub_efi_device_path_protocol_t;
|
|
|
ecb9bb |
|
|
|
ecb9bb |
+#define GRUB_EFI_DEVICE_PATH_IS_TYPE(dp, type, subtype) \
|
|
|
ecb9bb |
+ ((GRUB_EFI_DEVICE_PATH_TYPE(dp) == (type)) && \
|
|
|
ecb9bb |
+ (GRUB_EFI_DEVICE_PATH_SUBTYPE(dp) == (subtype)))
|
|
|
ecb9bb |
+
|
|
|
ecb9bb |
#define GRUB_EFI_DEVICE_PATH_TYPE(dp) ((dp)->type & 0x7f)
|
|
|
ecb9bb |
#define GRUB_EFI_DEVICE_PATH_SUBTYPE(dp) ((dp)->subtype)
|
|
|
ecb9bb |
#define GRUB_EFI_DEVICE_PATH_LENGTH(dp) ((dp)->length)
|
|
|
ecb9bb |
--
|
|
|
ecb9bb |
2.4.3
|
|
|
ecb9bb |
|