I'm trying to use the EFI simple network protocol:
http://wiki.phoenix.com/wiki/index.php/EFI_SIMPLE_NETWORK_PROTOCOL
to wait for an incoming ethernet packet. However, using QEMU, the WaitForPacket event never triggers even with incoming packets, and on real hardware the event always triggers immediately without any packets arriving. I can see my sample packets "on the wire" with tcpdump so I'm fairly confident I am supplying packets to it. Here is my code (boiled down to just this test case):
#include <efi.h>
#include <efilib.h>
EFI_HANDLE getNetHandle();
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
InitializeLib(ImageHandle, SystemTable);
EFI_GUID snpguid = EFI_SIMPLE_NETWORK_PROTOCOL;
EFI_HANDLE netHandle = getNetHandle();
EFI_STATUS status;
EFI_SIMPLE_NETWORK* net_if_struct;
status = uefi_call_wrapper(BS->HandleProtocol, 3,
netHandle, &snpguid, &net_if_struct);
Print(L"Main: HandleProtocol status: %r\n", status);
Print(L"Main: WaitForPacket event: %x\n", net_if_struct->WaitForPacket);
EFI_EVENT waitEvents[1];
waitEvents[0] = net_if_struct->WaitForPacket;
UINTN eventTriggered;
status = uefi_call_wrapper(BS->WaitForEvent, 3,
1, waitEvents, &eventTriggered);
Print(L"Main: WaitForEvent status: %r, event triggered: %d\n", status, eventTriggered);
return EFI_SUCCESS;
}
EFI_HANDLE getNetHandle()
{
UINTN numHandles = 0;
EFI_HANDLE* handles = NULL;
EFI_GUID SimpleNetworkGUID = EFI_SIMPLE_NETWORK_PROTOCOL;
EFI_STATUS status = uefi_call_wrapper(BS->LocateHandleBuffer, 5,
ByProtocol, &SimpleNetworkGUID, NULL, &numHandles, &handles);
if (status != EFI_SUCCESS)
Print(L"getNetHandle: Failed to LocateHandleBuffer (%d)\n", status);
else
Print(L"getNetHandle: LocateHandleBuffer OK (%d handles)\n", numHandles);
EFI_HANDLE toReturn = NULL;
if (numHandles == 1)
{
toReturn = handles[0];
}
FreePool(handles);
return toReturn;
}
Things I've tried / proof / clues I have:
When this runs the WaitForPacket event print line prints a non-null value so I am assuming the EFI system has created an event and left it ready in the EFI_SIMPLE_NETWORK struct.
I have tried assuming the other way that I need to create an event and put it in the struct, and then use that event to wait on, but it didn't make any difference.
I have other code which can send and receive packets (just about), so I think my understanding of the network handle and interface struct is reasonable, and my EFI hardware and QEMU is capable of network communication.
The documentation on how to use WaitForPacket is non-existent, to a point where it feels like this should be one of those things that just works. Documentation I have found is at the Phoenix wiki (linked above) and the 2899 page UEFI spec document version 2.7.
Despite my best Googling I can't find any examples of WaitForPacket being used in a GNU-EFI application.
I've tried starting and initialising the network hardware which seems necessary with QEMU but not with real hardware. I've also tried setting the hardware to promiscuous mode using ReceiveFilters() and broadcasting at it, but that made no difference either.
Any ideas??