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