iPXE
snponly.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <string.h>
27 #include <errno.h>
28 #include <ipxe/init.h>
29 #include <ipxe/efi/efi.h>
30 #include <ipxe/efi/efi_driver.h>
31 #include <ipxe/efi/efi_utils.h>
32 #include <ipxe/efi/mnpnet.h>
35 #include "snpnet.h"
36 #include "nii.h"
37 
38 /** @file
39  *
40  * EFI chainloaded-device-only driver
41  *
42  */
43 
44 /** A chainloaded protocol */
46  /** Protocol GUID */
48  /**
49  * Target device handle
50  *
51  * This is the uppermost handle on which the same protocol
52  * instance is installed as we find on the loaded image's
53  * device handle.
54  *
55  * We match against the protocol instance (rather than simply
56  * matching against the device handle itself) because some
57  * systems load us via a child of the underlying device, with
58  * a duplicate protocol installed on the child handle.
59  *
60  * We record the handle rather than the protocol instance
61  * pointer since the calls to DisconnectController() and
62  * ConnectController() may end up uninstalling and
63  * reinstalling the protocol instance.
64  */
66  /** Assume wireless devices are unusable */
68 };
69 
70 /** Chainloaded SNP protocol */
71 static struct chained_protocol chained_snp = {
73  .inhibit_wifi = 1,
74 };
75 
76 /** Chainloaded NII protocol */
77 static struct chained_protocol chained_nii = {
79  .inhibit_wifi = 1,
80 };
81 
82 /** Chainloaded MNP protocol */
83 static struct chained_protocol chained_mnp = {
85 };
86 
87 /**
88  * Locate chainloaded protocol
89  *
90  * @v chained Chainloaded protocol
91  */
92 static void chained_locate ( struct chained_protocol *chained ) {
95  void *match = NULL;
96  void *interface;
97  unsigned int skip;
98  int rc;
99 
100  /* Identify target device handle */
101  for ( skip = 0 ; ; skip++ ) {
102 
103  /* Locate handle supporting this protocol */
104  if ( ( rc = efi_locate_device ( device, chained->protocol,
105  &handle, skip ) ) != 0 ) {
106  if ( skip == 0 ) {
107  DBGC ( device, "CHAINED %s does not support "
108  "%s: %s\n", efi_handle_name ( device ),
109  efi_guid_ntoa ( chained->protocol ),
110  strerror ( rc ) );
111  }
112  break;
113  }
114 
115  /* Get protocol instance */
116  if ( ( rc = efi_open ( handle, chained->protocol,
117  &interface ) ) != 0 ) {
118  DBGC ( device, "CHAINED %s could not open %s on ",
120  efi_guid_ntoa ( chained->protocol ) );
121  DBGC ( device, "%s: %s\n",
122  efi_handle_name ( handle ), strerror ( rc ) );
123  break;
124  }
125 
126  /* Stop if we reach a non-matching protocol instance */
127  if ( match && ( match != interface ) ) {
128  DBGC ( device, "CHAINED %s found non-matching %s on ",
130  efi_guid_ntoa ( chained->protocol ) );
131  DBGC ( device, "%s\n", efi_handle_name ( handle ) );
132  break;
133  }
134 
135  /* Record this handle */
136  chained->device = handle;
137  match = interface;
138  DBGC ( device, "CHAINED %s found %s on ",
140  efi_guid_ntoa ( chained->protocol ) );
141  DBGC ( device, "%s\n", efi_handle_name ( chained->device ) );
142  }
143 }
144 
145 /**
146  * Check to see if driver supports a device
147  *
148  * @v device EFI device handle
149  * @v chained Chainloaded protocol
150  * @ret rc Return status code
151  */
153  struct chained_protocol *chained ) {
154  void *interface;
155  int rc;
156 
157  /* Get protocol */
158  if ( ( rc = efi_open ( device, chained->protocol,
159  &interface ) ) != 0 ) {
160  DBGCP ( device, "CHAINED %s is not a %s device\n",
162  efi_guid_ntoa ( chained->protocol ) );
163  return rc;
164  }
165 
166  /* Ignore non-matching handles */
167  if ( device != chained->device ) {
168  DBGC2 ( device, "CHAINED %s is not the chainloaded %s\n",
170  efi_guid_ntoa ( chained->protocol ) );
171  return -ENOTTY;
172  }
173  DBGC ( device, "CHAINED %s is the chainloaded %s\n",
175  efi_guid_ntoa ( chained->protocol ) );
176 
177  /* Check for wireless devices, if applicable */
178  if ( chained->inhibit_wifi &&
179  ( ( efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) ) {
180  DBGC ( device, "CHAINED %s is wireless: assuming vendor %s "
181  "driver is too unreliable to use\n",
183  efi_guid_ntoa ( chained->protocol ) );
184  return -ENOTTY;
185  }
186 
187  return 0;
188 }
189 
190 /**
191  * Check to see if driver supports a device
192  *
193  * @v device EFI device handle
194  * @ret rc Return status code
195  */
197 
198  return chained_supported ( device, &chained_snp );
199 }
200 
201 /**
202  * Check to see if driver supports a device
203  *
204  * @v device EFI device handle
205  * @ret rc Return status code
206  */
208 
209  return chained_supported ( device, &chained_nii );
210 }
211 
212 /**
213  * Check to see if driver supports a device
214  *
215  * @v device EFI device handle
216  * @ret rc Return status code
217  */
219 
220  return chained_supported ( device, &chained_mnp );
221 }
222 
223 /** EFI SNP chainloading-device-only driver */
224 struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_SNP ) = {
225  .name = "SNPONLY",
226  .supported = snponly_supported,
227  .exclude = snpnet_exclude,
228  .start = snpnet_start,
229  .stop = snpnet_stop,
230 };
231 
232 /** EFI NII chainloading-device-only driver */
233 struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NII ) = {
234  .name = "NIIONLY",
235  .supported = niionly_supported,
236  .exclude = nii_exclude,
237  .start = nii_start,
238  .stop = nii_stop,
239 };
240 
241 /** EFI MNP chainloading-device-only driver */
242 struct efi_driver mnponly_driver __efi_driver ( EFI_DRIVER_MNP ) = {
243  .name = "MNPONLY",
244  .supported = mnponly_supported,
245  .start = mnpnet_start,
246  .stop = mnpnet_stop,
247 };
248 
249 /**
250  * Initialise EFI chainloaded-device-only driver
251  *
252  */
253 static void chained_init ( void ) {
254 
258 }
259 
260 /** EFI chainloaded-device-only initialisation function */
261 struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = {
262  .name = "chained",
263  .initialise = chained_init,
264 };
EFI_GUID efi_nii31_protocol_guid
Network interface identifier protocol GUID (new version)
Definition: efi_guid.c:308
static int chained_supported(EFI_HANDLE device, struct chained_protocol *chained)
Check to see if driver supports a device.
Definition: snponly.c:152
NII driver.
static int snponly_supported(EFI_HANDLE device)
Check to see if driver supports a device.
Definition: snponly.c:196
EFI_LOADED_IMAGE_PROTOCOL * efi_loaded_image
Loaded image protocol for this image.
Definition: efi_init.c:38
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
EFI_HANDLE device
Target device handle.
Definition: snponly.c:65
EFI driver interface.
128 bit buffer containing a unique identifier value.
Definition: Base.h:215
Error codes.
int nii_start(struct efi_device *efidev)
Attach driver to device.
Definition: nii.c:1286
void snpnet_stop(struct efi_device *efidev)
Detach driver from device.
Definition: snpnet.c:844
int inhibit_wifi
Assume wireless devices are unusable.
Definition: snponly.c:67
#define efi_test(handle, protocol)
Test protocol existence.
Definition: efi.h:432
EFI_GUID efi_simple_network_protocol_guid
Simple network protocol GUID.
Definition: efi_guid.c:340
#define DBGC(...)
Definition: compiler.h:505
EFI Network Interface Identifier Protocol.
void nii_stop(struct efi_device *efidev)
Detach driver from device.
Definition: nii.c:1397
EFI_GUID efi_managed_network_service_binding_protocol_guid
Managed network service binding protocol GUID.
Definition: efi_guid.c:284
int nii_exclude(EFI_HANDLE device)
Exclude existing drivers.
Definition: nii.c:1266
A chainloaded protocol.
Definition: snponly.c:45
EFI utilities.
int snpnet_start(struct efi_device *efidev)
Attach driver to device.
Definition: snpnet.c:727
static int mnponly_supported(EFI_HANDLE device)
Check to see if driver supports a device.
Definition: snponly.c:218
A hardware device.
Definition: device.h:76
static struct chained_protocol chained_nii
Chainloaded NII protocol.
Definition: snponly.c:77
#define EFI_DRIVER_SNP
SNP protocol drivers.
Definition: efi_driver.h:74
An initialisation function.
Definition: init.h:14
static struct chained_protocol chained_snp
Chainloaded SNP protocol.
Definition: snponly.c:71
An object interface.
Definition: interface.h:124
const char * name
Definition: init.h:15
The EFI_SIMPLE_NETWORK_PROTOCOL provides services to initialize a network interface,...
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
Definition: efi_debug.c:652
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
#define EFI_DRIVER_MNP
MNP protocol drivers.
Definition: efi_driver.h:75
static int niionly_supported(EFI_HANDLE device)
Check to see if driver supports a device.
Definition: snponly.c:207
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition: efi.h:443
MNP NIC driver.
SNP NIC driver.
static void chained_init(void)
Initialise EFI chainloaded-device-only driver.
Definition: snponly.c:253
int efi_locate_device(EFI_HANDLE device, EFI_GUID *protocol, EFI_HANDLE *parent, unsigned int skip)
Locate parent device supporting a given protocol.
Definition: efi_utils.c:45
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_guid.c:725
void mnpnet_stop(struct efi_device *efidev)
Detach driver from device.
Definition: mnpnet.c:474
struct efi_driver snponly_driver __efi_driver(EFI_DRIVER_SNP)
EFI SNP chainloading-device-only driver.
EFI API.
EFI_GUID * protocol
Protocol GUID.
Definition: snponly.c:47
An EFI driver.
Definition: efi_driver.h:33
EFI_GUID efi_wifi2_protocol_guid
WiFi 2 protocol GUID.
Definition: efi_guid.c:436
#define DBGC2(...)
Definition: compiler.h:522
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:594
struct init_fn chained_init_fn __init_fn(INIT_LATE)
EFI chainloaded-device-only initialisation function.
const char * name
Name.
Definition: efi_driver.h:35
#define DBGCP(...)
Definition: compiler.h:539
static void chained_locate(struct chained_protocol *chained)
Locate chainloaded protocol.
Definition: snponly.c:92
int snpnet_exclude(EFI_HANDLE device)
Exclude existing drivers.
Definition: snpnet.c:692
#define INIT_LATE
Late initialisation.
Definition: init.h:32
#define EFI_DRIVER_NII
NII protocol drivers.
Definition: efi_driver.h:73
uint16_t handle
Handle.
Definition: smbios.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
int mnpnet_start(struct efi_device *efidev)
Attach driver to device.
Definition: mnpnet.c:369
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
Definition: efi.h:61
EFI_HANDLE DeviceHandle
The device handle that the EFI Image was loaded from.
Definition: LoadedImage.h:55
static struct chained_protocol chained_mnp
Chainloaded MNP protocol.
Definition: snponly.c:83