]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Bind to only the topmost instance of the SNP or NII protocols
authorMichael Brown <mcb30@ipxe.org>
Mon, 23 Jan 2023 19:18:21 +0000 (19:18 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 23 Jan 2023 19:27:13 +0000 (19:27 +0000)
UEFI has the mildly annoying habit of installing copies of the
EFI_SIMPLE_NETWORK_PROTOCOL instance on the IPv4 and IPv6 child device
handles.  This can cause iPXE's SNP driver to attempt to bind to a
copy of the EFI_SIMPLE_NETWORK_PROTOCOL that iPXE itself provided on a
different handle.

Fix by refusing to bind to an SNP (or NII) handle if there exists
another instance of the same protocol further up the device path (on
the basis that we always want to bind to the highest possible device).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/net/efi/snp.c

index fbd60690203dfb73c7f7c51cddaace9b143206e5..1920cdbc53cb8716297efb5af55168b7cd845714 100644 (file)
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/efi/efi.h>
 #include <ipxe/efi/efi_driver.h>
 #include <ipxe/efi/efi_snp.h>
+#include <ipxe/efi/efi_utils.h>
 #include "snpnet.h"
 #include "nii.h"
 
@@ -40,31 +41,46 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  * Check to see if driver supports a device
  *
  * @v device           EFI device handle
+ * @v protocol         Protocol GUID
  * @ret rc             Return status code
  */
-static int snp_supported ( EFI_HANDLE device ) {
+static int snp_nii_supported ( EFI_HANDLE device, EFI_GUID *protocol ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+       EFI_HANDLE parent;
        EFI_STATUS efirc;
+       int rc;
 
        /* Check that this is not a device we are providing ourselves */
        if ( find_snpdev ( device ) != NULL ) {
-               DBGCP ( device, "SNP %s is provided by this binary\n",
+               DBGCP ( device, "HANDLE %s is provided by this binary\n",
                        efi_handle_name ( device ) );
                return -ENOTTY;
        }
 
-       /* Test for presence of simple network protocol */
-       if ( ( efirc = bs->OpenProtocol ( device,
-                                         &efi_simple_network_protocol_guid,
+       /* Test for presence of protocol */
+       if ( ( efirc = bs->OpenProtocol ( device, protocol,
                                          NULL, efi_image_handle, device,
                                          EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
-               DBGCP ( device, "SNP %s is not an SNP device\n",
-                       efi_handle_name ( device ) );
+               DBGCP ( device, "HANDLE %s is not a %s device\n",
+                       efi_handle_name ( device ),
+                       efi_guid_ntoa ( protocol ) );
                return -EEFI ( efirc );
        }
-       DBGC ( device, "SNP %s is an SNP device\n",
-              efi_handle_name ( device ) );
 
+       /* Check that there are no instances of this protocol further
+        * up this device path.
+        */
+       if ( ( rc = efi_locate_device ( device, protocol,
+                                       &parent, 1 ) ) == 0 ) {
+               DBGC2 ( device, "HANDLE %s has %s-supporting parent ",
+                       efi_handle_name ( device ),
+                       efi_guid_ntoa ( protocol ) );
+               DBGC2 ( device, "%s\n", efi_handle_name ( parent ) );
+               return -ENOTTY;
+       }
+
+       DBGC ( device, "HANDLE %s is a %s device\n",
+              efi_handle_name ( device ), efi_guid_ntoa ( protocol ) );
        return 0;
 }
 
@@ -74,30 +90,20 @@ static int snp_supported ( EFI_HANDLE device ) {
  * @v device           EFI device handle
  * @ret rc             Return status code
  */
-static int nii_supported ( EFI_HANDLE device ) {
-       EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
-       EFI_STATUS efirc;
+static int snp_supported ( EFI_HANDLE device ) {
 
-       /* Check that this is not a device we are providing ourselves */
-       if ( find_snpdev ( device ) != NULL ) {
-               DBGCP ( device, "NII %s is provided by this binary\n",
-                       efi_handle_name ( device ) );
-               return -ENOTTY;
-       }
+       return snp_nii_supported ( device, &efi_simple_network_protocol_guid );
+}
 
-       /* Test for presence of NII protocol */
-       if ( ( efirc = bs->OpenProtocol ( device,
-                                         &efi_nii31_protocol_guid,
-                                         NULL, efi_image_handle, device,
-                                         EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
-               DBGCP ( device, "NII %s is not an NII device\n",
-                       efi_handle_name ( device ) );
-               return -EEFI ( efirc );
-       }
-       DBGC ( device, "NII %s is an NII device\n",
-              efi_handle_name ( device ) );
+/**
+ * Check to see if driver supports a device
+ *
+ * @v device           EFI device handle
+ * @ret rc             Return status code
+ */
+static int nii_supported ( EFI_HANDLE device ) {
 
-       return 0;
+       return snp_nii_supported ( device, &efi_nii31_protocol_guid );
 }
 
 /** EFI SNP driver */