]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Assume that vendor wireless drivers are unusable via SNP
authorMichael Brown <mcb30@ipxe.org>
Tue, 15 Jul 2025 08:12:54 +0000 (09:12 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 15 Jul 2025 08:12:54 +0000 (09:12 +0100)
The UEFI model for wireless network boot cannot sensibly be described
without cursing.  Commit 758a504 ("[efi] Inhibit calls to Shutdown()
for wireless SNP devices") attempts to work around some of the known
issues.

Experimentation shows that on at least some platforms (observed with a
Lenovo ThinkPad T14s Gen 5) the vendor SNP driver is broken to the
point of being unusable in anything other than the single use case
envisioned by the firwmare authors.  Doing almost anything directly
via the SNP protocol interface has a greater than 50% chance of
locking up the system.

Assume, in the absence of any evidence to the contrary so far, that
vendor SNP drivers for wireless network devices are so badly written
as to be unusable.  Refuse to even attempt to interact with these
drivers via the SNP or NII protocol interfaces.

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

index 3c839d9685c7465629efc6f7a9f255420cce8fbd..212c712df81c2a8a2022a3f969c3ac76d2f6f0f3 100644 (file)
@@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 static int mnp_supported ( EFI_HANDLE device ) {
        EFI_GUID *binding = &efi_managed_network_service_binding_protocol_guid;
 
-       return snpnet_supported ( device, binding );
+       return snpnet_supported ( device, binding, 0 );
 }
 
 /** EFI MNP driver */
index 2e0d9df3ac35e7d5aab5fa19a72138e26fe738fe..a675050e407ec4ccd0b9210e719c84d0f7a9b813 100644 (file)
@@ -41,8 +41,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  * @ret rc             Return status code
  */
 static int snp_supported ( EFI_HANDLE device ) {
+       EFI_GUID *protocol = &efi_simple_network_protocol_guid;
 
-       return snpnet_supported ( device, &efi_simple_network_protocol_guid );
+       return snpnet_supported ( device, protocol, 1 );
 }
 
 /**
@@ -52,8 +53,9 @@ static int snp_supported ( EFI_HANDLE device ) {
  * @ret rc             Return status code
  */
 static int nii_supported ( EFI_HANDLE device ) {
+       EFI_GUID *protocol = &efi_nii31_protocol_guid;
 
-       return snpnet_supported ( device, &efi_nii31_protocol_guid );
+       return snpnet_supported ( device, protocol, 1 );
 }
 
 /** EFI SNP driver */
index 109eecf0144da31986ba3bc28e73b9ece47feb32..8427b6ce3275d8edb2b0c9ee9df50c1357593787 100644 (file)
@@ -504,9 +504,11 @@ static struct net_device_operations snpnet_operations = {
  *
  * @v device           EFI device handle
  * @v protocol         Protocol GUID
+ * @v inhibit_wifi     Inhibit wireless devices
  * @ret rc             Return status code
  */
-int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ) {
+int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol,
+                      int inhibit_wifi ) {
        EFI_HANDLE parent;
        int rc;
 
@@ -536,9 +538,19 @@ int snpnet_supported ( EFI_HANDLE device, EFI_GUID *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 ) );
+
+       /* Check for wireless devices, if applicable */
+       if ( inhibit_wifi &&
+            ( ( efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) ) {
+               DBGC ( device, "HANDLE %s is wireless: assuming vendor %s "
+                      "driver is too unreliable to use\n",
+                      efi_handle_name ( device ),
+                      efi_guid_ntoa ( protocol ) );
+               return -ENOTTY;
+       }
+
        return 0;
 }
 
index d3602a589c15412501ce74f16e0f54452b0a1463..5073502104834dfd207c505c6672d4f809e6eeba 100644 (file)
@@ -11,7 +11,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 struct efi_device;
 
-extern int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol );
+extern int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol,
+                             int inhibit_wifi );
 extern int snpnet_exclude ( EFI_HANDLE device );
 extern int snpnet_start ( struct efi_device *efidev );
 extern void snpnet_stop ( struct efi_device *efidev );
index 88c74ed4282fff86600db353eecfcf65300e8c0e..f0a5277a287970dfbaa5bf57bf603145a216deb1 100644 (file)
@@ -63,16 +63,20 @@ struct chained_protocol {
         * reinstalling the protocol instance.
         */
        EFI_HANDLE device;
+       /** Assume wireless devices are unusable */
+       int inhibit_wifi;
 };
 
 /** Chainloaded SNP protocol */
 static struct chained_protocol chained_snp = {
        .protocol = &efi_simple_network_protocol_guid,
+       .inhibit_wifi = 1,
 };
 
 /** Chainloaded NII protocol */
 static struct chained_protocol chained_nii = {
        .protocol = &efi_nii31_protocol_guid,
+       .inhibit_wifi = 1,
 };
 
 /** Chainloaded MNP protocol */
@@ -166,10 +170,20 @@ static int chained_supported ( EFI_HANDLE device,
                        efi_guid_ntoa ( chained->protocol ) );
                return -ENOTTY;
        }
-
        DBGC ( device, "CHAINED %s is the chainloaded %s\n",
               efi_handle_name ( device ),
               efi_guid_ntoa ( chained->protocol ) );
+
+       /* Check for wireless devices, if applicable */
+       if ( chained->inhibit_wifi &&
+            ( ( efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) ) {
+               DBGC ( device, "CHAINED %s is wireless: assuming vendor %s "
+                      "driver is too unreliable to use\n",
+                      efi_handle_name ( device ),
+                      efi_guid_ntoa ( chained->protocol ) );
+               return -ENOTTY;
+       }
+
        return 0;
 }