summaryrefslogtreecommitdiffstats
path: root/src/drivers/net/efi/snponly.c
diff options
context:
space:
mode:
authorMichael Brown2014-08-20 14:15:00 +0200
committerMichael Brown2014-09-04 16:39:02 +0200
commit4c5b7945c34392dda8a22c0759c15f78f90bb8a3 (patch)
tree945b43274c6d96534b2c6f673586d46a15f522d3 /src/drivers/net/efi/snponly.c
parent[efi] Wrap any images loaded by our wrapped image (diff)
downloadipxe-4c5b7945c34392dda8a22c0759c15f78f90bb8a3.tar.gz
ipxe-4c5b7945c34392dda8a22c0759c15f78f90bb8a3.tar.xz
ipxe-4c5b7945c34392dda8a22c0759c15f78f90bb8a3.zip
[efi] Use the SNP protocol instance to match the SNP chainloading device
Some systems will install a child of the SNP device and use this as our loaded image's device handle, duplicating the installation of the underlying SNP protocol onto the child device handle. On such systems, we want to end up driving the parent device (and disconnecting any other drivers, such as MNP, which may be attached to the parent device). Fix by recording the SNP protocol instance at initialisation time, and using this to match against device handles (rather than simply comparing the handles themselves). Reported-by: Jarrod Johnson <jarrod.b.johnson@gmail.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/net/efi/snponly.c')
-rw-r--r--src/drivers/net/efi/snponly.c97
1 files changed, 89 insertions, 8 deletions
diff --git a/src/drivers/net/efi/snponly.c b/src/drivers/net/efi/snponly.c
index d8dc86ad..d454ed20 100644
--- a/src/drivers/net/efi/snponly.c
+++ b/src/drivers/net/efi/snponly.c
@@ -20,38 +20,119 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <errno.h>
+#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
#include "snpnet.h"
/** @file
*
- * SNP chainloaded-device-only driver
+ * SNP chainloading-device-only driver
*
*/
/**
+ * SNP protocol instance installed on the loaded image's device handle
+ *
+ * We match against the SNP protocol instance (rather than simply
+ * matching against the device handle itself) because some systems
+ * load us via a child of the SNP device, with a duplicate SNP
+ * protocol installed on the child handle.
+ */
+static EFI_SIMPLE_NETWORK_PROTOCOL *snponly;
+
+/**
* Check to see if driver supports a device
*
* @v device EFI device handle
* @ret rc Return status code
*/
static int snponly_supported ( EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+ union {
+ EFI_SIMPLE_NETWORK_PROTOCOL *snp;
+ void *interface;
+ } snp;
+ int rc;
- /* Check that this device is our loaded image's device */
- if ( device != efi_loaded_image->DeviceHandle )
- return -ENOTTY;
+ /* Get SNP protocol */
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_simple_network_protocol_guid,
+ &snp.interface, efi_image_handle,
+ device,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
+ rc = -EEFI ( efirc );
+ DBGCP ( device, "SNPONLY %p %s is not an SNP device\n",
+ device, efi_handle_name ( device ) );
+ goto err_not_snp;
+ }
- DBGC ( device, "SNP %p %s is the SNP chainloading device\n",
- device, efi_handle_name ( device ) );
+ /* Test for a match against the chainloading device */
+ if ( snp.snp != snponly ) {
+ DBGC ( device, "SNPONLY %p %s SNP %p is not the "
+ "chainloading SNP\n", device,
+ efi_handle_name ( device ), snp.snp );
+ rc = -ENOTTY;
+ goto err_not_snponly;
+ }
- return 0;
+ /* Success */
+ rc = 0;
+ DBGC ( device, "SNPONLY %p %s SNP %p is the chainloading SNP\n",
+ device, efi_handle_name ( device ), snp.snp );
+
+ err_not_snponly:
+ bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
+ efi_image_handle, device );
+ err_not_snp:
+ return rc;
}
-/** EFI SNP driver */
+/** EFI chainloading-device-only driver */
struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
.name = "SNPONLY",
.supported = snponly_supported,
.start = snpnet_start,
.stop = snpnet_stop,
};
+
+/**
+ * Initialise EFI chainloading-device-only driver
+ *
+ */
+static void snponly_init ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE device = efi_loaded_image->DeviceHandle;
+ union {
+ EFI_SIMPLE_NETWORK_PROTOCOL *snp;
+ void *interface;
+ } snp;
+ EFI_STATUS efirc;
+
+ /* Look for SNP protocol on the loaded image's device handle */
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_simple_network_protocol_guid,
+ &snp.interface, efi_image_handle,
+ device,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
+ DBGC ( device, "SNPONLY %p %s is not an SNP device\n",
+ device, efi_handle_name ( device ) );
+ goto err_open_protocol;
+ }
+
+ /* Record SNP protocol instance */
+ snponly = snp.snp;
+ DBGC ( device, "SNPONLY %p %s found chainloading SNP %p\n",
+ device, efi_handle_name ( device ), snponly );
+
+ err_open_protocol:
+ bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
+ efi_image_handle, device );
+}
+
+/** EFI chainloading-device-only initialisation function */
+struct init_fn snponly_init_fn __init_fn ( INIT_LATE ) = {
+ .initialise = snponly_init,
+};