Browse Source

[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>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
4c5b7945c3
1 changed files with 89 additions and 8 deletions
  1. 89
    8
      src/drivers/net/efi/snponly.c

+ 89
- 8
src/drivers/net/efi/snponly.c View File

@@ -20,16 +20,28 @@
20 20
 FILE_LICENCE ( GPL2_OR_LATER );
21 21
 
22 22
 #include <errno.h>
23
+#include <ipxe/init.h>
23 24
 #include <ipxe/efi/efi.h>
24 25
 #include <ipxe/efi/efi_driver.h>
26
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
25 27
 #include "snpnet.h"
26 28
 
27 29
 /** @file
28 30
  *
29
- * SNP chainloaded-device-only driver
31
+ * SNP chainloading-device-only driver
30 32
  *
31 33
  */
32 34
 
35
+/**
36
+ * SNP protocol instance installed on the loaded image's device handle
37
+ *
38
+ * We match against the SNP protocol instance (rather than simply
39
+ * matching against the device handle itself) because some systems
40
+ * load us via a child of the SNP device, with a duplicate SNP
41
+ * protocol installed on the child handle.
42
+ */
43
+static EFI_SIMPLE_NETWORK_PROTOCOL *snponly;
44
+
33 45
 /**
34 46
  * Check to see if driver supports a device
35 47
  *
@@ -37,21 +49,90 @@ FILE_LICENCE ( GPL2_OR_LATER );
37 49
  * @ret rc		Return status code
38 50
  */
39 51
 static int snponly_supported ( EFI_HANDLE device ) {
52
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
53
+	EFI_STATUS efirc;
54
+	union {
55
+		EFI_SIMPLE_NETWORK_PROTOCOL *snp;
56
+		void *interface;
57
+	} snp;
58
+	int rc;
40 59
 
41
-	/* Check that this device is our loaded image's device */
42
-	if ( device != efi_loaded_image->DeviceHandle )
43
-		return -ENOTTY;
60
+	/* Get SNP protocol */
61
+	if ( ( efirc = bs->OpenProtocol ( device,
62
+					  &efi_simple_network_protocol_guid,
63
+					  &snp.interface, efi_image_handle,
64
+					  device,
65
+					  EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
66
+		rc = -EEFI ( efirc );
67
+		DBGCP ( device, "SNPONLY %p %s is not an SNP device\n",
68
+			device, efi_handle_name ( device ) );
69
+		goto err_not_snp;
70
+	}
44 71
 
45
-	DBGC ( device, "SNP %p %s is the SNP chainloading device\n",
46
-	       device, efi_handle_name ( device ) );
72
+	/* Test for a match against the chainloading device */
73
+	if ( snp.snp != snponly ) {
74
+		DBGC ( device, "SNPONLY %p %s SNP %p is not the "
75
+		       "chainloading SNP\n", device,
76
+		       efi_handle_name ( device ), snp.snp );
77
+		rc = -ENOTTY;
78
+		goto err_not_snponly;
79
+	}
47 80
 
48
-	return 0;
81
+	/* Success */
82
+	rc = 0;
83
+	DBGC ( device, "SNPONLY %p %s SNP %p is the chainloading SNP\n",
84
+	       device, efi_handle_name ( device ), snp.snp );
85
+
86
+ err_not_snponly:
87
+	bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
88
+			    efi_image_handle, device );
89
+ err_not_snp:
90
+	return rc;
49 91
 }
50 92
 
51
-/** EFI SNP driver */
93
+/** EFI chainloading-device-only driver */
52 94
 struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
53 95
 	.name = "SNPONLY",
54 96
 	.supported = snponly_supported,
55 97
 	.start = snpnet_start,
56 98
 	.stop = snpnet_stop,
57 99
 };
100
+
101
+/**
102
+ * Initialise EFI chainloading-device-only driver
103
+ *
104
+ */
105
+static void snponly_init ( void ) {
106
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
107
+	EFI_HANDLE device = efi_loaded_image->DeviceHandle;
108
+	union {
109
+		EFI_SIMPLE_NETWORK_PROTOCOL *snp;
110
+		void *interface;
111
+	} snp;
112
+	EFI_STATUS efirc;
113
+
114
+	/* Look for SNP protocol on the loaded image's device handle */
115
+	if ( ( efirc = bs->OpenProtocol ( device,
116
+					  &efi_simple_network_protocol_guid,
117
+					  &snp.interface, efi_image_handle,
118
+					  device,
119
+					  EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
120
+		DBGC ( device, "SNPONLY %p %s is not an SNP device\n",
121
+		       device, efi_handle_name ( device ) );
122
+		goto err_open_protocol;
123
+	}
124
+
125
+	/* Record SNP protocol instance */
126
+	snponly = snp.snp;
127
+	DBGC ( device, "SNPONLY %p %s found chainloading SNP %p\n",
128
+	       device, efi_handle_name ( device ), snponly );
129
+
130
+ err_open_protocol:
131
+	bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
132
+			    efi_image_handle, device );
133
+}
134
+
135
+/** EFI chainloading-device-only initialisation function */
136
+struct init_fn snponly_init_fn __init_fn ( INIT_LATE ) = {
137
+	.initialise = snponly_init,
138
+};

Loading…
Cancel
Save