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>
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 */
* @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 );
}
/**
* @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 */
*
* @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;
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;
}
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 );
* 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 */
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;
}