summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-01-23 19:18:21 +0000
committerMichael Brown <mcb30@ipxe.org>2023-01-23 19:27:13 +0000
commit68734b9a4dafa540e5333d7af3849b59a10f7a93 (patch)
treed4b2d9f1b69c4fcc13571c30dd98041263f92b66
parent2fef0c541e4e2417fc285c4d9ddfcb6f23f394ad (diff)
downloadqemu-ipxe-68734b9a4dafa540e5333d7af3849b59a10f7a93.tar.gz
[efi] Bind to only the topmost instance of the SNP or NII protocolssnploop
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>
-rw-r--r--src/drivers/net/efi/snp.c66
1 files changed, 36 insertions, 30 deletions
diff --git a/src/drivers/net/efi/snp.c b/src/drivers/net/efi/snp.c
index fbd60690..1920cdbc 100644
--- a/src/drivers/net/efi/snp.c
+++ b/src/drivers/net/efi/snp.c
@@ -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 */