diff options
Diffstat (limited to 'src/drivers/net/efi')
| -rw-r--r-- | src/drivers/net/efi/mnp.c | 4 | ||||
| -rw-r--r-- | src/drivers/net/efi/mnpnet.c | 26 | ||||
| -rw-r--r-- | src/drivers/net/efi/nii.c | 67 | ||||
| -rw-r--r-- | src/drivers/net/efi/nii.h | 2 | ||||
| -rw-r--r-- | src/drivers/net/efi/snp.c | 16 | ||||
| -rw-r--r-- | src/drivers/net/efi/snpnet.c | 245 | ||||
| -rw-r--r-- | src/drivers/net/efi/snpnet.h | 5 | ||||
| -rw-r--r-- | src/drivers/net/efi/snponly.c | 57 |
8 files changed, 307 insertions, 115 deletions
diff --git a/src/drivers/net/efi/mnp.c b/src/drivers/net/efi/mnp.c index 33218fb10..212c712df 100644 --- a/src/drivers/net/efi/mnp.c +++ b/src/drivers/net/efi/mnp.c @@ -44,11 +44,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); 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 */ -struct efi_driver mnp_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver mnp_driver __efi_driver ( EFI_DRIVER_MNP ) = { .name = "MNP", .supported = mnp_supported, .start = mnpnet_start, diff --git a/src/drivers/net/efi/mnpnet.c b/src/drivers/net/efi/mnpnet.c index eb4b129c7..fe0ebaadb 100644 --- a/src/drivers/net/efi/mnpnet.c +++ b/src/drivers/net/efi/mnpnet.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); /** @file * @@ -367,14 +368,9 @@ static struct net_device_operations mnpnet_operations = { * @ret rc Return status code */ int mnpnet_start ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE device = efidev->device; EFI_GUID *binding = &efi_managed_network_service_binding_protocol_guid; EFI_SIMPLE_NETWORK_MODE mode; - union { - EFI_MANAGED_NETWORK_PROTOCOL *mnp; - void *interface; - } u; struct net_device *netdev; struct mnp_nic *mnp; EFI_STATUS efirc; @@ -408,18 +404,13 @@ int mnpnet_start ( struct efi_device *efidev ) { } /* Open MNP protocol */ - if ( ( efirc = bs->OpenProtocol ( efidev->child, - &efi_managed_network_protocol_guid, - &u.interface, efi_image_handle, - efidev->child, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open_by_driver ( efidev->child, + &efi_managed_network_protocol_guid, + &mnp->mnp ) ) != 0 ) { DBGC ( mnp, "MNP %s could not open MNP protocol: %s\n", efi_handle_name ( device ), strerror ( rc ) ); goto err_open; } - mnp->mnp = u.mnp; /* Get configuration */ efirc = mnp->mnp->GetModeData ( mnp->mnp, NULL, &mode ); @@ -464,8 +455,8 @@ int mnpnet_start ( struct efi_device *efidev ) { err_ll_addr_len: err_hw_addr_len: err_mode: - bs->CloseProtocol ( efidev->child, &efi_managed_network_protocol_guid, - efi_image_handle, efidev->child ); + efi_close_by_driver ( efidev->child, + &efi_managed_network_protocol_guid ); err_open: efi_service_del ( device, binding, efidev->child ); err_service: @@ -482,7 +473,6 @@ int mnpnet_start ( struct efi_device *efidev ) { * @v efidev EFI device */ void mnpnet_stop ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID *binding = &efi_managed_network_service_binding_protocol_guid; struct net_device *netdev = efidev_get_drvdata ( efidev ); struct mnp_nic *mnp = netdev->priv; @@ -491,8 +481,8 @@ void mnpnet_stop ( struct efi_device *efidev ) { unregister_netdev ( netdev ); /* Close MNP protocol */ - bs->CloseProtocol ( efidev->child, &efi_managed_network_protocol_guid, - efi_image_handle, efidev->child ); + efi_close_by_driver ( efidev->child, + &efi_managed_network_protocol_guid ); /* Remove MNP child (unless whole system shutdown is in progress) */ if ( ! efi_shutdown_in_progress ) diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index 16e9e10df..d1adf3d44 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <string.h> #include <strings.h> @@ -177,7 +178,7 @@ struct nii_nic { size_t mtu; /** Hardware transmit/receive buffer */ - userptr_t buffer; + void *buffer; /** Hardware transmit/receive buffer length */ size_t buffer_len; @@ -210,10 +211,6 @@ static int nii_pci_open ( struct nii_nic *nii ) { EFI_HANDLE device = nii->efidev->device; EFI_HANDLE pci_device; union { - EFI_PCI_IO_PROTOCOL *pci_io; - void *interface; - } pci_io; - union { EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *acpi; void *resource; } desc; @@ -230,17 +227,18 @@ static int nii_pci_open ( struct nii_nic *nii ) { } nii->pci_device = pci_device; - /* Open PCI I/O protocol */ - if ( ( efirc = bs->OpenProtocol ( pci_device, &efi_pci_io_protocol_guid, - &pci_io.interface, efi_image_handle, - device, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); + /* Open PCI I/O protocol + * + * We cannot open this safely as a by-driver open, since doing + * so would disconnect the underlying NII driver. We must + * therefore use an unsafe open. + */ + if ( ( rc = efi_open_unsafe ( pci_device, &efi_pci_io_protocol_guid, + &nii->pci_io ) ) != 0 ) { DBGC ( nii, "NII %s could not open PCI I/O protocol: %s\n", nii->dev.name, strerror ( rc ) ); goto err_open; } - nii->pci_io = pci_io.pci_io; /* Identify memory and I/O BARs */ nii->mem_bar = PCI_MAX_BAR; @@ -280,8 +278,7 @@ static int nii_pci_open ( struct nii_nic *nii ) { return 0; err_get_bar_attributes: - bs->CloseProtocol ( pci_device, &efi_pci_io_protocol_guid, - efi_image_handle, device ); + efi_close_unsafe ( pci_device, &efi_pci_io_protocol_guid ); err_open: err_locate: return rc; @@ -294,7 +291,6 @@ static int nii_pci_open ( struct nii_nic *nii ) { * @ret rc Return status code */ static void nii_pci_close ( struct nii_nic *nii ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct nii_mapping *map; struct nii_mapping *tmp; @@ -308,8 +304,7 @@ static void nii_pci_close ( struct nii_nic *nii ) { } /* Close protocols */ - bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid, - efi_image_handle, nii->efidev->device ); + efi_close_unsafe ( nii->pci_device, &efi_pci_io_protocol_guid ); } /** @@ -1264,18 +1259,35 @@ static struct net_device_operations nii_operations = { }; /** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +int nii_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_nii31_protocol_guid; + int rc; + + /* Exclude existing NII protocol drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "NII %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** * Attach driver to device * * @v efidev EFI device * @ret rc Return status code */ int nii_start ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE device = efidev->device; struct net_device *netdev; struct nii_nic *nii; - void *interface; - EFI_STATUS efirc; int rc; /* Allocate and initialise structure */ @@ -1300,17 +1312,13 @@ int nii_start ( struct efi_device *efidev ) { netdev->dev = &nii->dev; /* Open NII protocol */ - if ( ( efirc = bs->OpenProtocol ( device, &efi_nii31_protocol_guid, - &interface, efi_image_handle, device, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open_by_driver ( device, &efi_nii31_protocol_guid, + &nii->nii ) ) != 0 ) { DBGC ( nii, "NII %s cannot open NII protocol: %s\n", nii->dev.name, strerror ( rc ) ); DBGC_EFI_OPENERS ( device, device, &efi_nii31_protocol_guid ); goto err_open_protocol; } - nii->nii = interface; /* Locate UNDI and entry point */ nii->undi = ( ( void * ) ( intptr_t ) nii->nii->Id ); @@ -1373,8 +1381,7 @@ int nii_start ( struct efi_device *efidev ) { err_pci_open: err_hw_undi: err_no_undi: - bs->CloseProtocol ( device, &efi_nii31_protocol_guid, - efi_image_handle, device ); + efi_close_by_driver ( device, &efi_nii31_protocol_guid ); err_open_protocol: list_del ( &nii->dev.siblings ); netdev_nullify ( netdev ); @@ -1389,7 +1396,6 @@ int nii_start ( struct efi_device *efidev ) { * @v efidev EFI device */ void nii_stop ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct net_device *netdev = efidev_get_drvdata ( efidev ); struct nii_nic *nii = netdev->priv; EFI_HANDLE device = efidev->device; @@ -1404,8 +1410,7 @@ void nii_stop ( struct efi_device *efidev ) { nii_pci_close ( nii ); /* Close NII protocol */ - bs->CloseProtocol ( device, &efi_nii31_protocol_guid, - efi_image_handle, device ); + efi_close_by_driver ( device, &efi_nii31_protocol_guid ); /* Free network device */ list_del ( &nii->dev.siblings ); diff --git a/src/drivers/net/efi/nii.h b/src/drivers/net/efi/nii.h index c10be9db5..e0b07f0a5 100644 --- a/src/drivers/net/efi/nii.h +++ b/src/drivers/net/efi/nii.h @@ -8,9 +8,11 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); struct efi_device; +extern int nii_exclude ( EFI_HANDLE device ); extern int nii_start ( struct efi_device *efidev ); extern void nii_stop ( struct efi_device *efidev ); diff --git a/src/drivers/net/efi/snp.c b/src/drivers/net/efi/snp.c index cac8b38e2..854fa872d 100644 --- a/src/drivers/net/efi/snp.c +++ b/src/drivers/net/efi/snp.c @@ -41,8 +41,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @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 ); } /** @@ -52,22 +53,29 @@ static int snp_supported ( EFI_HANDLE device ) { * @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 */ -struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_SNP ) = { .name = "SNP", .supported = snp_supported, + .exclude = snpnet_exclude, .start = snpnet_start, .stop = snpnet_stop, }; /** EFI NII driver */ -struct efi_driver nii_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver nii_driver __efi_driver ( EFI_DRIVER_NII ) = { .name = "NII", .supported = nii_supported, + .exclude = nii_exclude, .start = nii_start, .stop = nii_stop, }; + +/** Drag in MNP driver */ +REQUIRING_SYMBOL ( snp_driver ); +REQUIRE_SYMBOL ( mnp_driver ); diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index 6ce731d78..6046f0a1e 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -18,6 +18,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER ); +FILE_SECBOOT ( PERMITTED ); #include <stdlib.h> #include <stdio.h> @@ -86,6 +87,14 @@ struct snp_nic { */ #define SNP_RX_PAD 8 +/** An SNP interface patch to inhibit shutdown for insomniac devices */ +struct snp_insomniac_patch { + /** Original Shutdown() method */ + EFI_SIMPLE_NETWORK_SHUTDOWN shutdown; + /** Original Stop() method */ + EFI_SIMPLE_NETWORK_STOP stop; +}; + /** * Format SNP MAC address (for debugging) * @@ -387,9 +396,10 @@ static int snpnet_open ( struct net_device *netdev ) { /* Initialise NIC, retrying multiple times if link stays down */ for ( retry = 0 ; ; ) { - /* Initialise NIC */ - if ( ( efirc = snp->snp->Initialize ( snp->snp, - 0, 0 ) ) != 0 ) { + /* Initialise NIC, if not already initialised */ + if ( ( mode->State != EfiSimpleNetworkInitialized ) && + ( ( efirc = snp->snp->Initialize ( snp->snp, + 0, 0 ) ) != 0 ) ) { rc = -EEFI ( efirc ); snpnet_dump_mode ( netdev ); DBGC ( snp, "SNP %s could not initialise: %s\n", @@ -413,11 +423,13 @@ static int snpnet_open ( struct net_device *netdev ) { /* Delay to allow time for link to establish */ mdelay ( SNP_INITIALIZE_RETRY_DELAY_MS ); - /* Shut down and retry; this is sometimes necessary in - * order to persuade the underlying SNP driver to - * actually update the link state. + /* Shut down and retry (unless device is insomniac); + * this is sometimes necessary in order to persuade + * the underlying SNP driver to actually update the + * link state. */ - if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) { + if ( ( ! netdev_insomniac ( netdev ) ) && + ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); snpnet_dump_mode ( netdev ); DBGC ( snp, "SNP %s could not shut down: %s\n", @@ -455,8 +467,11 @@ static void snpnet_close ( struct net_device *netdev ) { EFI_STATUS efirc; int rc; - /* Shut down NIC (unless whole system shutdown is in progress) */ + /* Shut down NIC (unless whole system shutdown is in progress, + * or device is insomniac). + */ if ( ( ! efi_shutdown_in_progress ) && + ( ! netdev_insomniac ( netdev ) ) && ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); DBGC ( snp, "SNP %s could not shut down: %s\n", @@ -490,12 +505,12 @@ static struct net_device_operations snpnet_operations = { * * @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 ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; +int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol, + int inhibit_wifi ) { EFI_HANDLE parent; - EFI_STATUS efirc; int rc; /* Check that this is not a device we are providing ourselves */ @@ -506,13 +521,11 @@ int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ) { } /* Test for presence of protocol */ - if ( ( efirc = bs->OpenProtocol ( device, protocol, - NULL, efi_image_handle, device, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ + if ( ( rc = efi_test ( device, protocol ) ) != 0 ) { DBGCP ( device, "HANDLE %s is not a %s device\n", efi_handle_name ( device ), efi_guid_ntoa ( protocol ) ); - return -EEFI ( efirc ); + return rc; } /* Check that there are no instances of this protocol further @@ -526,35 +539,205 @@ int snpnet_supported ( EFI_HANDLE device, EFI_GUID *protocol ) { 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; +} + +/** + * Check if device must be insomniac + * + * @v device EFI device handle + * @v is_insomniac Device must be insomniac + */ +static int snpnet_is_insomniac ( EFI_HANDLE device ) { + int rc; + + /* Check for wireless devices + * + * The UEFI model for wireless network configuration is + * somewhat underdefined. At the time of writing, the EDK2 + * "UEFI WiFi Connection Manager" driver provides only one way + * to configure wireless network credentials, which is to + * enter them interactively via an HII form. Credentials are + * not stored (or exposed via any protocol interface), and so + * any temporary disconnection from the wireless network will + * inevitably leave the interface in an unusable state that + * cannot be recovered without user intervention. + * + * Experimentation shows that at least some wireless network + * drivers will disconnect from the wireless network when the + * SNP Shutdown() method is called, or if the device is not + * polled sufficiently frequently to maintain its association + * to the network. We therefore inhibit calls to Shutdown() + * and Stop() for any such SNP protocol interfaces, and mark + * our network device as insomniac so that it will be polled + * even when closed. + */ + if ( ( rc = efi_test ( device, &efi_wifi2_protocol_guid ) ) == 0 ) { + DBGC ( device, "SNP %s is wireless: assuming insomniac\n", + efi_handle_name ( device ) ); + return 1; + } + return 0; } /** + * Ignore shutdown attempt + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +snpnet_do_nothing ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused ) { + + return 0; +} + +/** + * Patch SNP protocol interface to prevent shutdown + * + * @v device EFI device handle + * @v patch Interface patch + * @ret rc Return status code + */ +static int snpnet_insomniac_patch ( EFI_HANDLE device, + struct snp_insomniac_patch *patch ) { + EFI_SIMPLE_NETWORK_PROTOCOL *interface; + int rc; + + /* Open interface for ephemeral use */ + if ( ( rc = efi_open ( device, &efi_simple_network_protocol_guid, + &interface ) ) != 0 ) { + DBGC ( device, "SNP %s cannot open SNP protocol for patching: " + "%s\n", efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + /* Record original Shutdown() and Stop() methods */ + patch->shutdown = interface->Shutdown; + patch->stop = interface->Stop; + + /* Inhibit other UEFI drivers' calls to Shutdown() and Stop() + * + * This is necessary since disconnecting the MnpDxe driver + * will attempt to shut down the SNP device, which would leave + * us with an unusable device. + */ + interface->Shutdown = snpnet_do_nothing; + interface->Stop = snpnet_do_nothing; + DBGC ( device, "SNP %s patched to inhibit shutdown\n", + efi_handle_name ( device ) ); + + return 0; +} + +/** + * Restore patched SNP protocol interface + * + * @v device EFI device handle + * @v patch Interface patch to fill in + * @ret rc Return status code + */ +static int snpnet_insomniac_restore ( EFI_HANDLE device, + struct snp_insomniac_patch *patch ) { + EFI_SIMPLE_NETWORK_PROTOCOL *interface; + int rc; + + /* Avoid returning uninitialised data on error */ + memset ( patch, 0, sizeof ( *patch ) ); + + /* Open interface for ephemeral use */ + if ( ( rc = efi_open ( device, &efi_simple_network_protocol_guid, + &interface ) ) != 0 ) { + DBGC ( device, "SNP %s cannot open patched SNP protocol: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + /* Restore original Shutdown() and Stop() methods, if possible */ + if ( interface->Shutdown == snpnet_do_nothing ) + interface->Shutdown = patch->shutdown; + if ( interface->Stop == snpnet_do_nothing ) + interface->Stop = patch->stop; + + /* Check that original methods were restored (by us or others) */ + if ( ( interface->Shutdown != patch->shutdown ) || + ( interface->Stop != patch->stop ) ) { + DBGC ( device, "SNP %s could not restore patched SNP " + "protocol\n", efi_handle_name ( device ) ); + return -EBUSY; + } + + return 0; +} + +/** + * Exclude existing drivers + * + * @v device EFI device handle + * @ret rc Return status code + */ +int snpnet_exclude ( EFI_HANDLE device ) { + EFI_GUID *protocol = &efi_simple_network_protocol_guid; + struct snp_insomniac_patch patch; + int insomniac; + int rc; + + /* Check if this is a device that must not ever be shut down */ + insomniac = snpnet_is_insomniac ( device ); + + /* Inhibit calls to Shutdown() and Stop(), if applicable */ + if ( insomniac && + ( ( rc = snpnet_insomniac_patch ( device, &patch ) ) != 0 ) ) { + goto err_patch; + } + + /* Exclude existing SNP drivers */ + if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) { + DBGC ( device, "SNP %s could not exclude drivers: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_exclude; + } + + err_exclude: + if ( insomniac ) + snpnet_insomniac_restore ( device, &patch ); + err_patch: + return rc; +} + +/** * Attach driver to device * * @v efidev EFI device * @ret rc Return status code */ int snpnet_start ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE device = efidev->device; + EFI_SIMPLE_NETWORK_PROTOCOL *interface; EFI_SIMPLE_NETWORK_MODE *mode; struct net_device *netdev; struct snp_nic *snp; - void *interface; EFI_STATUS efirc; int rc; /* Open SNP protocol */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_simple_network_protocol_guid, - &interface, efi_image_handle, device, - ( EFI_OPEN_PROTOCOL_BY_DRIVER | - EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open_by_driver ( device, + &efi_simple_network_protocol_guid, + &interface ) ) != 0 ) { DBGC ( device, "SNP %s cannot open SNP protocol: %s\n", efi_handle_name ( device ), strerror ( rc ) ); DBGC_EFI_OPENERS ( device, device, @@ -583,7 +766,11 @@ int snpnet_start ( struct efi_device *efidev ) { INIT_LIST_HEAD ( &snp->dev.children ); netdev->dev = &snp->dev; - /* Bring to the Started state */ + /* Check if device is insomniac */ + if ( snpnet_is_insomniac ( device ) ) + netdev->state |= NETDEV_INSOMNIAC; + + /* Bring to the correct state for a closed interface */ if ( ( mode->State == EfiSimpleNetworkStopped ) && ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); @@ -592,6 +779,7 @@ int snpnet_start ( struct efi_device *efidev ) { goto err_start; } if ( ( mode->State == EfiSimpleNetworkInitialized ) && + ( ! netdev_insomniac ( netdev ) ) && ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); DBGC ( device, "SNP %s could not shut down: %s\n", @@ -644,8 +832,7 @@ int snpnet_start ( struct efi_device *efidev ) { netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: - bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, - efi_image_handle, device ); + efi_close_by_driver ( device, &efi_simple_network_protocol_guid ); err_open_protocol: return rc; } @@ -656,7 +843,6 @@ int snpnet_start ( struct efi_device *efidev ) { * @v efidev EFI device */ void snpnet_stop ( struct efi_device *efidev ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct net_device *netdev = efidev_get_drvdata ( efidev ); struct snp_nic *snp = netdev->priv; EFI_HANDLE device = efidev->device; @@ -681,6 +867,5 @@ void snpnet_stop ( struct efi_device *efidev ) { netdev_put ( netdev ); /* Close SNP protocol */ - bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, - efi_image_handle, device ); + efi_close_by_driver ( device, &efi_simple_network_protocol_guid ); } diff --git a/src/drivers/net/efi/snpnet.h b/src/drivers/net/efi/snpnet.h index 4699c7892..a361a99c0 100644 --- a/src/drivers/net/efi/snpnet.h +++ b/src/drivers/net/efi/snpnet.h @@ -8,10 +8,13 @@ */ FILE_LICENCE ( GPL2_OR_LATER ); +FILE_SECBOOT ( PERMITTED ); 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 ); diff --git a/src/drivers/net/efi/snponly.c b/src/drivers/net/efi/snponly.c index 2ae63fc06..b7231ce01 100644 --- a/src/drivers/net/efi/snponly.c +++ b/src/drivers/net/efi/snponly.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <string.h> #include <errno.h> @@ -63,16 +64,20 @@ struct chained_protocol { * 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 */ @@ -86,13 +91,11 @@ static struct chained_protocol chained_mnp = { * @v chained Chainloaded protocol */ static void chained_locate ( struct chained_protocol *chained ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE device = efi_loaded_image->DeviceHandle; EFI_HANDLE handle; void *match = NULL; void *interface; unsigned int skip; - EFI_STATUS efirc; int rc; /* Identify target device handle */ @@ -111,11 +114,8 @@ static void chained_locate ( struct chained_protocol *chained ) { } /* Get protocol instance */ - if ( ( efirc = bs->OpenProtocol ( - handle, chained->protocol, &interface, - efi_image_handle, handle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL )) != 0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open ( handle, chained->protocol, + &interface ) ) != 0 ) { DBGC ( device, "CHAINED %s could not open %s on ", efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol ) ); @@ -123,8 +123,6 @@ static void chained_locate ( struct chained_protocol *chained ) { efi_handle_name ( handle ), strerror ( rc ) ); break; } - bs->CloseProtocol ( handle, chained->protocol, - efi_image_handle, handle ); /* Stop if we reach a non-matching protocol instance */ if ( match && ( match != interface ) ) { @@ -154,20 +152,16 @@ static void chained_locate ( struct chained_protocol *chained ) { */ static int chained_supported ( EFI_HANDLE device, struct chained_protocol *chained ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; void *interface; - EFI_STATUS efirc; int rc; /* Get protocol */ - if ( ( efirc = bs->OpenProtocol ( device, chained->protocol, &interface, - efi_image_handle, device, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); + if ( ( rc = efi_open ( device, chained->protocol, + &interface ) ) != 0 ) { DBGCP ( device, "CHAINED %s is not a %s device\n", efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol ) ); - goto err_open_protocol; + return rc; } /* Ignore non-matching handles */ @@ -175,21 +169,23 @@ static int chained_supported ( EFI_HANDLE device, DBGC2 ( device, "CHAINED %s is not the chainloaded %s\n", efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol ) ); - rc = -ENOTTY; - goto err_no_match; + return -ENOTTY; } - - /* Success */ - rc = 0; DBGC ( device, "CHAINED %s is the chainloaded %s\n", efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol ) ); - err_no_match: - bs->CloseProtocol ( device, chained->protocol, efi_image_handle, - device ); - err_open_protocol: - return rc; + /* 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; } /** @@ -226,23 +222,25 @@ static int mnponly_supported ( EFI_HANDLE device ) { } /** EFI SNP chainloading-device-only driver */ -struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_SNP ) = { .name = "SNPONLY", .supported = snponly_supported, + .exclude = snpnet_exclude, .start = snpnet_start, .stop = snpnet_stop, }; /** EFI NII chainloading-device-only driver */ -struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NII ) = { .name = "NIIONLY", .supported = niionly_supported, + .exclude = nii_exclude, .start = nii_start, .stop = nii_stop, }; /** EFI MNP chainloading-device-only driver */ -struct efi_driver mnponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { +struct efi_driver mnponly_driver __efi_driver ( EFI_DRIVER_MNP ) = { .name = "MNPONLY", .supported = mnponly_supported, .start = mnpnet_start, @@ -262,5 +260,6 @@ static void chained_init ( void ) { /** EFI chainloaded-device-only initialisation function */ struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = { + .name = "chained", .initialise = chained_init, }; |
