this broken firmware and uses GET_PROTOCOL instead of EXCLUSIVE. This also
keeps the original protocol we use when scanning the cards and leaves the
initialization stuff for ->open. Thanks,
Signed-off-by: Josef Bacik <address@hidden>
---
grub-core/net/drivers/efi/efinet.c | 99 ++++++++++++++++++--------------------
1 file changed, 46 insertions(+), 53 deletions(-)
diff --git a/grub-core/net/drivers/efi/efinet.c
b/grub-core/net/drivers/efi/efinet.c
index c8f80a1..5a207fd 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -156,59 +156,40 @@ get_card_packet (struct grub_net_card *dev)
static grub_err_t
open_card (struct grub_net_card *dev)
{
- grub_efi_simple_network_t *net;
+ grub_efi_simple_network_t *net = dev->efi_net;
- /* 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 (net)
+ if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
+ return grub_error (GRUB_ERR_NET_NO_CARD, "%s: card stopped",
+ dev->name);
+
+ if (net->mode->state == GRUB_EFI_NETWORK_STARTED
+ && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
+ return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed",
+ dev->name);
+
+ /* Enable hardware receive filters if driver declares support for it.
+ We need unicast and broadcast and additionaly all nodes and
+ solicited multicast for IPv6. Solicited multicast is per-IPv6
+ address and we currently do not have API to do it so simply
+ try to enable receive of all multicast packets or evertyhing in
+ the worst case (i386 PXE driver always enables promiscuous too).
+
+ This does trust firmware to do what it claims to do.
+ */
+ if (net->mode->receive_filter_mask)
{
- if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
- && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
- return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net start failed",
- dev->name);
-
- if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
- return grub_error (GRUB_ERR_NET_NO_CARD, "%s: card stopped",
- dev->name);
-
- if (net->mode->state == GRUB_EFI_NETWORK_STARTED
- && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
- return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed",
- dev->name);
-
- /* Enable hardware receive filters if driver declares support for it.
- We need unicast and broadcast and additionaly all nodes and
- solicited multicast for IPv6. Solicited multicast is per-IPv6
- address and we currently do not have API to do it so simply
- try to enable receive of all multicast packets or evertyhing in
- the worst case (i386 PXE driver always enables promiscuous too).
-
- This does trust firmware to do what it claims to do.
- */
- if (net->mode->receive_filter_mask)
- {
- grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
- GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
-
GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
-
- filters &= net->mode->receive_filter_mask;
- if (!(filters &
GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST))
- filters |= (net->mode->receive_filter_mask &
- GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS);
+ grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+ GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
- efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL);
- }
+ filters &= net->mode->receive_filter_mask;
+ if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST))
+ filters |= (net->mode->receive_filter_mask &
+ GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS);
- 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;
+ efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL);
}
- /* If it failed we just try to run as best as we can */
return GRUB_ERR_NONE;
}
@@ -278,12 +259,26 @@ grub_efinet_is_mac_device (struct grub_net_card *card)
return 0;
}
+static grub_efi_uint32_t
+grub_snp_attributes (void)
+{
+ /* Some firmware will completely screw up the transition to exclusive SNP,
+ doing things like not honoring receive filters or taking multiple seconds
+ to make the switch over. So don't bother using exclusive in this case.
+ */
+ if (!grub_memcmp(grub_efi_system_table->firmware_vendor, "A", 1) &&
+ grub_efi_system_table->firmware_revision == (grub_efi_uint32_t)262798)