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 FILE_SECBOOT ( PERMITTED );
26 
27 #include <string.h>
28 #include <errno.h>
29 #include <ipxe/init.h>
30 #include <ipxe/efi/efi.h>
31 #include <ipxe/efi/efi_driver.h>
32 #include <ipxe/efi/efi_utils.h>
33 #include <ipxe/efi/mnpnet.h>
36 #include "snpnet.h"
37 #include "nii.h"
38 
39 /** @file
40  *
41  * EFI chainloaded-device-only driver
42  *
43  */
44 
45 /** A chainloaded protocol */
47  /** Protocol GUID */
49  /**
50  * Target device handle
51  *
52  * This is the uppermost handle on which the same protocol
53  * instance is installed as we find on the loaded image's
54  * device handle.
55  *
56  * We match against the protocol instance (rather than simply
57  * matching against the device handle itself) because some
58  * systems load us via a child of the underlying device, with
59  * a duplicate protocol installed on the child handle.
60  *
61  * We record the handle rather than the protocol instance
62  * pointer since the calls to DisconnectController() and
63  * ConnectController() may end up uninstalling and
64  * reinstalling the protocol instance.
65  */
67  /** Assume wireless devices are unusable */
69 };
70 
71 /** Chainloaded SNP protocol */
72 static struct chained_protocol chained_snp = {
74  .inhibit_wifi = 1,
75 };
76 
77 /** Chainloaded NII protocol */
78 static struct chained_protocol chained_nii = {
80  .inhibit_wifi = 1,
81 };
82 
83 /** Chainloaded MNP protocol */
84 static struct chained_protocol chained_mnp = {
86 };
87 
88 /**
89  * Locate chainloaded protocol
90  *
91  * @v chained Chainloaded protocol
92  */
93 static void chained_locate ( struct chained_protocol *chained ) {
96  void *match = NULL;
97  void *interface;
98  unsigned int skip;
99  int rc;
100 
101  /* Identify target device handle */
102  for ( skip = 0 ; ; skip++ ) {
103 
104  /* Locate handle supporting this protocol */
105  if ( ( rc = efi_locate_device ( device, chained->protocol,
106  &handle, skip ) ) != 0 ) {
107  if ( skip == 0 ) {
108  DBGC ( device, "CHAINED %s does not support "
109  "%s: %s\n", efi_handle_name ( device ),
110  efi_guid_ntoa ( chained->protocol ),
111  strerror ( rc ) );
112  }
113  break;
114  }
115 
116  /* Get protocol instance */
117  if ( ( rc = efi_open ( handle, chained->protocol,
118  &interface ) ) != 0 ) {
119  DBGC ( device, "CHAINED %s could not open %s on ",
121  efi_guid_ntoa ( chained->protocol ) );
122  DBGC ( device, "%s: %s\n",
123  efi_handle_name ( handle ), strerror ( rc ) );
124  break;
125  }
126 
127  /* Stop if we reach a non-matching protocol instance */
128  if ( match && ( match != interface ) ) {
129  DBGC ( device, "CHAINED %s found non-matching %s on ",
131  efi_guid_ntoa ( chained->protocol ) );
132  DBGC ( device, "%s\n", efi_handle_name ( handle ) );
133  break;
134  }
135 
136  /* Record this handle */
137  chained->device = handle;
138  match = interface;
139  DBGC ( device, "CHAINED %s found %s on ",
141  efi_guid_ntoa ( chained->protocol ) );
142  DBGC ( device, "%s\n", efi_handle_name ( chained->device ) );
143  }
144 }
145 
146 /**
147  * Check to see if driver supports a device
148  *
149  * @v device EFI device handle
150  * @v chained Chainloaded protocol
151  * @ret rc Return status code
152  */
154  struct chained_protocol *chained ) {
155  void *interface;
156  int rc;
157 
158  /* Get protocol */
159  if ( ( rc = efi_open ( device, chained->protocol,
160  &interface ) ) != 0 ) {
161  DBGCP ( device, "CHAINED %s is not a %s device\n",
163  efi_guid_ntoa ( chained->protocol ) );
164  return rc;
165  }
166 
167  /* Ignore non-matching handles */
168  if ( device != chained->device ) {
169  DBGC2 ( device, "CHAINED %s is not the chainloaded %s\n",
171  efi_guid_ntoa ( chained->protocol ) );
172  return -ENOTTY;
173  }
174  DBGC ( device, "CHAINED %s is the chainloaded %s\n",
176  efi_guid_ntoa ( chained->protocol ) );
177 
178  /* Check for wireless devices, if applicable */
179  if ( chained->inhibit_wifi &&
180  ( ( efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) ) {
181  DBGC ( device, "CHAINED %s is wireless: assuming vendor %s "
182  "driver is too unreliable to use\n",
184  efi_guid_ntoa ( chained->protocol ) );
185  return -ENOTTY;
186  }
187 
188  return 0;
189 }
190 
191 /**
192  * Check to see if driver supports a device
193  *
194  * @v device EFI device handle
195  * @ret rc Return status code
196  */
198 
199  return chained_supported ( device, &chained_snp );
200 }
201 
202 /**
203  * Check to see if driver supports a device
204  *
205  * @v device EFI device handle
206  * @ret rc Return status code
207  */
209 
210  return chained_supported ( device, &chained_nii );
211 }
212 
213 /**
214  * Check to see if driver supports a device
215  *
216  * @v device EFI device handle
217  * @ret rc Return status code
218  */
220 
221  return chained_supported ( device, &chained_mnp );
222 }
223 
224 /** EFI SNP chainloading-device-only driver */
225 struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_SNP ) = {
226  .name = "SNPONLY",
227  .supported = snponly_supported,
228  .exclude = snpnet_exclude,
229  .start = snpnet_start,
230  .stop = snpnet_stop,
231 };
232 
233 /** EFI NII chainloading-device-only driver */
234 struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NII ) = {
235  .name = "NIIONLY",
236  .supported = niionly_supported,
237  .exclude = nii_exclude,
238  .start = nii_start,
239  .stop = nii_stop,
240 };
241 
242 /** EFI MNP chainloading-device-only driver */
243 struct efi_driver mnponly_driver __efi_driver ( EFI_DRIVER_MNP ) = {
244  .name = "MNPONLY",
245  .supported = mnponly_supported,
246  .start = mnpnet_start,
247  .stop = mnpnet_stop,
248 };
249 
250 /**
251  * Initialise EFI chainloaded-device-only driver
252  *
253  */
254 static void chained_init ( void ) {
255 
259 }
260 
261 /** EFI chainloaded-device-only initialisation function */
262 struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = {
263  .name = "chained",
264  .initialise = chained_init,
265 };
EFI_GUID efi_nii31_protocol_guid
Network interface identifier protocol GUID (new version)
Definition: efi_guid.c:309
static int chained_supported(EFI_HANDLE device, struct chained_protocol *chained)
Check to see if driver supports a device.
Definition: snponly.c:153
NII driver.
static int snponly_supported(EFI_HANDLE device)
Check to see if driver supports a device.
Definition: snponly.c:197
EFI_LOADED_IMAGE_PROTOCOL * efi_loaded_image
Loaded image protocol for this image.
Definition: efi_init.c:39
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
EFI_HANDLE device
Target device handle.
Definition: snponly.c:66
EFI driver interface.
128 bit buffer containing a unique identifier value.
Definition: Base.h:216
Error codes.
int nii_start(struct efi_device *efidev)
Attach driver to device.
Definition: nii.c:1287
void snpnet_stop(struct efi_device *efidev)
Detach driver from device.
Definition: snpnet.c:845
int inhibit_wifi
Assume wireless devices are unusable.
Definition: snponly.c:68
#define efi_test(handle, protocol)
Test protocol existence.
Definition: efi.h:433
EFI_GUID efi_simple_network_protocol_guid
Simple network protocol GUID.
Definition: efi_guid.c:341
#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:1398
EFI_GUID efi_managed_network_service_binding_protocol_guid
Managed network service binding protocol GUID.
Definition: efi_guid.c:285
int nii_exclude(EFI_HANDLE device)
Exclude existing drivers.
Definition: nii.c:1267
A chainloaded protocol.
Definition: snponly.c:46
EFI utilities.
int snpnet_start(struct efi_device *efidev)
Attach driver to device.
Definition: snpnet.c:728
static int mnponly_supported(EFI_HANDLE device)
Check to see if driver supports a device.
Definition: snponly.c:219
A hardware device.
Definition: device.h:77
static struct chained_protocol chained_nii
Chainloaded NII protocol.
Definition: snponly.c:78
#define EFI_DRIVER_SNP
SNP protocol drivers.
Definition: efi_driver.h:75
An initialisation function.
Definition: init.h:15
static struct chained_protocol chained_snp
Chainloaded SNP protocol.
Definition: snponly.c:72
An object interface.
Definition: interface.h:125
const char * name
Definition: init.h:16
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:79
#define EFI_DRIVER_MNP
MNP protocol drivers.
Definition: efi_driver.h:76
static int niionly_supported(EFI_HANDLE device)
Check to see if driver supports a device.
Definition: snponly.c:208
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition: efi.h:444
MNP NIC driver.
SNP NIC driver.
static void chained_init(void)
Initialise EFI chainloaded-device-only driver.
Definition: snponly.c:254
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:46
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_guid.c:726
void mnpnet_stop(struct efi_device *efidev)
Detach driver from device.
Definition: mnpnet.c:475
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:48
An EFI driver.
Definition: efi_driver.h:34
EFI_GUID efi_wifi2_protocol_guid
WiFi 2 protocol GUID.
Definition: efi_guid.c:437
#define DBGC2(...)
Definition: compiler.h:522
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:595
struct init_fn chained_init_fn __init_fn(INIT_LATE)
EFI chainloaded-device-only initialisation function.
const char * name
Name.
Definition: efi_driver.h:36
#define DBGCP(...)
Definition: compiler.h:539
static void chained_locate(struct chained_protocol *chained)
Locate chainloaded protocol.
Definition: snponly.c:93
int snpnet_exclude(EFI_HANDLE device)
Exclude existing drivers.
Definition: snpnet.c:693
#define INIT_LATE
Late initialisation.
Definition: init.h:33
#define EFI_DRIVER_NII
NII protocol drivers.
Definition: efi_driver.h:74
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
int mnpnet_start(struct efi_device *efidev)
Attach driver to device.
Definition: mnpnet.c:370
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
Definition: efi.h:62
EFI_HANDLE DeviceHandle
The device handle that the EFI Image was loaded from.
Definition: LoadedImage.h:56
FILE_SECBOOT(PERMITTED)
static struct chained_protocol chained_mnp
Chainloaded MNP protocol.
Definition: snponly.c:84