In the context of the implementation of the EFI_LOAD_FILE2_PROTOCOL for the initial ramdisk it was observed that opening the SNP protocol failed. https://lists.gnu.org/archive/html/grub-devel/2021-10/msg00020.html This is due to an incorrect call to CloseProtocol().
The first parameter of CloseProtocol() is the handle, not the interface. We call OpenProtocol() with ControllerHandle = NULL. Hence we must also call CloseProtcol with ControllerHandel = NULL. Each call of OpenProtocol() for the same network card handle is expected to return the same interface pointer. If we want to close the protocol which we opened non-exclusively when searching for a card, we have to do this before opening the protocol exclusively. As there is no guarantee that we successfully open the protocol add checks in the transmit and receive functions. Reported-by: Andreas Schwab <sch...@linux-m68k.org> Signed-off-by: Heinrich Schuchardt <heinrich.schucha...@canonical.com> --- grub-core/net/drivers/efi/efinet.c | 32 ++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c index 5388f952b..3f2ff03f5 100644 --- a/grub-core/net/drivers/efi/efinet.c +++ b/grub-core/net/drivers/efi/efinet.c @@ -39,6 +39,8 @@ send_card_buffer (struct grub_net_card *dev, grub_uint64_t limit_time = grub_get_time_ms () + 4000; void *txbuf; + if (!net) + return grub_error (GRUB_ERR_IO, N_("couldn't send network packet")); if (dev->txbusy) while (1) { @@ -101,6 +103,9 @@ get_card_packet (struct grub_net_card *dev) struct grub_net_buff *nb; int i; + if (!net) + return NULL; + for (i = 0; i < 2; i++) { if (!dev->rcvbuf) @@ -148,11 +153,23 @@ open_card (struct grub_net_card *dev) { grub_efi_simple_network_t *net; - /* Try to reopen SNP exlusively to close any active MNP protocol instance - that may compete for packet polling + if (dev->efi_net) + { + efi_call_4 (grub_efi_system_table->boot_services->close_protocol, + dev->efi_handle, &net_io_guid, + grub_efi_image_handle, 0); + dev->efi_net = NULL; + } + /* + * Try to reopen SNP exlusively to close any active MNP protocol instance + * that may compete for packet polling */ net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid, GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE); + /* If exclusively fails, try non-exclusively. */ + if (!net) + net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (net) { if (net->mode->state == GRUB_EFI_NETWORK_STOPPED @@ -192,13 +209,12 @@ open_card (struct grub_net_card *dev) efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL); } - efi_call_4 (grub_efi_system_table->boot_services->close_protocol, - dev->efi_net, &net_io_guid, - grub_efi_image_handle, dev->efi_handle); dev->efi_net = net; + } else { + return grub_error (GRUB_ERR_NET_NO_CARD, "%s: can't open protocol", + dev->name); } - /* If it failed we just try to run as best as we can */ return GRUB_ERR_NONE; } @@ -208,8 +224,8 @@ close_card (struct grub_net_card *dev) efi_call_1 (dev->efi_net->shutdown, dev->efi_net); efi_call_1 (dev->efi_net->stop, dev->efi_net); efi_call_4 (grub_efi_system_table->boot_services->close_protocol, - dev->efi_net, &net_io_guid, - grub_efi_image_handle, dev->efi_handle); + dev->efi_handle, &net_io_guid, + grub_efi_image_handle, 0); } static struct grub_net_card_driver efidriver = -- 2.32.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel