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