I want to develop an application to be automatically executed from startup.nsh in EFI shell. This application should send raw bytes to an ip address and receive some back. I looked everywhere for explanation and example for the implementation of simple network protocol in my code but found nothin. Can someone explain and show a code example using gnu_efi libaries?
Asked
Active
Viewed 1,217 times
0
-
The UEFI specification contains a complete sample using the HTTP protocol. The steps are nearly the same for UDP and TCP (call Connect before sending any data if you use TCP). – MiSimon Apr 12 '21 at 06:12
-
I dont need to use the http protocol just the simple network protocol for sending a simple char and receive one back. I read about handle protocol but I can’t understand how to actually implement all these things together – Raffaele Bertani Apr 13 '21 at 07:02
-
The title says "TCP or UDP" you need the TCPv4 or the UDP protocol to do that, the SNP (simple network protocol) should not be used directly, you should use the MNP instead. But you can only send raw packets with either SNP or MNP. – MiSimon Apr 13 '21 at 07:22
-
Thanks a lot. This UDPv4 PROTOCOL looks like the solution. But the main problem remains the same. Could you or someone provide a few lines of example to send a character “S” to a x.y.w.z:33333? – Raffaele Bertani Apr 13 '21 at 10:10
-
I can provide you a simple sample based on EDK2, you just need to use the uefi_call_wrapper around every UEFI method to make it run with gnu-efi. – MiSimon Apr 13 '21 at 10:53
-
https://stackoverflow.com/questions/67073808/writing-my-first-efi-application-with-gnu-efi This question explain better my situation. Thanks a lot – Raffaele Bertani Apr 13 '21 at 11:20
-
@MiSimon here an error main.c:284:58: error: request for member ‘DestroyChild’ in something not a structure or union 284 | Status = uefi_call_wrapper(Udp4ServiceBindingProtocol->DestroyChild,2,Udp4ServiceBindingProtocol,Udp4ChildHandle); – Raffaele Bertani Apr 15 '21 at 12:20
-
Please create a github (or similar) project and post the link. – MiSimon Apr 15 '21 at 14:39
-
I forgot the InitializeLib. Tonight I’m going to try again if it still won’t work I’ll create a GitHub – Raffaele Bertani Apr 15 '21 at 16:32
-
@MiSimon here's my project: https://github.com/RapRaf/AlexaBootEFI – Raffaele Bertani Apr 15 '21 at 20:29
-
@MiSimon sorry, it sends nothin. It executes and exits without listening for the reply. No errors but no packets sent from the efi application. What could it be? – Raffaele Bertani Apr 20 '21 at 13:23
1 Answers
0
Here is a sample how to send and receive UDP packets with EDK2, porting it to gnu-efi should be an easy task, wrap all gBS->, gRT-> and protocolXY calls with the uefi_call_wrapper.
Change the global values to match your client and server.
#include <Uefi.h>
#include <Library\UefiLib.h>
#include <Protocol\ServiceBinding.h>
#include <Protocol\Udp4.h>
#include <Protocol\SimpleNetwork.h>
#include <Protocol\ManagedNetwork.h>
#include <Protocol\Ip4.h>
#ifndef LOG
#define LOG(fmt, ...) AsciiPrint(fmt, __VA_ARGS__)
#endif
#ifndef TRACE
#define TRACE(status) LOG("Status: '%r', Function: '%a', File: '%a', Line: '%d'\r\n", status, __FUNCTION__, __FILE__, __LINE__)
#endif
static EFI_GUID gEfiUdp4ServiceBindingProtocolGuid = EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID;
static EFI_GUID gEfiUdp4ProtocolGuid = EFI_UDP4_PROTOCOL_GUID;
extern EFI_BOOT_SERVICES *gBS;
extern EFI_RUNTIME_SERVICES *gRT;
static BOOLEAN gTransmitCompleteFlag = FALSE;
static BOOLEAN gReceiveCompleteFlag = FALSE;
/*
Configuration
*/
static EFI_IPv4_ADDRESS gLocalAddress = { 10, 0, 2, 200 };
static EFI_IPv4_ADDRESS gSubnetMask = { 255, 255, 255, 0 };
static UINT16 gLocalPort = 0;
static EFI_IPv4_ADDRESS gRemoteAddress = { 10, 0, 2, 180 };
static UINT16 gRemotePort = 4444;
static VOID
EFIAPI
TransmitEventCallback(
IN EFI_EVENT Event,
IN void *UserData)
{
gTransmitCompleteFlag = TRUE;
}
static VOID
EFIAPI
ReceiveEventCallback(
IN EFI_EVENT Event,
IN void *UserData)
{
gReceiveCompleteFlag = TRUE;
}
static EFI_STATUS
EFIAPI
WaitForFlag(
IN BOOLEAN *Flag,
IN EFI_UDP4_PROTOCOL *Udp4Protocol OPTIONAL,
IN UINTN Timeout)
{
EFI_STATUS Status;
UINT8 LastSecond = MAX_UINT8;
UINT8 Timer = 0;
EFI_TIME CurrentTime;
while (!*Flag && (Timeout == 0 || Timer < Timeout)) {
if (Udp4Protocol) {
Udp4Protocol->Poll(
Udp4Protocol);
}
// use gRT->GetTime to exit this loop
Status = gRT->GetTime(&CurrentTime, NULL);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
if (LastSecond != CurrentTime.Second) {
LastSecond = CurrentTime.Second;
Timer++;
}
}
return *Flag ? EFI_SUCCESS : EFI_TIMEOUT;
}
EFI_STATUS
EFIAPI
UefiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status;
EFI_UDP4_CONFIG_DATA Udp4ConfigData;
EFI_UDP4_COMPLETION_TOKEN Udp4ReceiveCompletionToken;
EFI_UDP4_COMPLETION_TOKEN Udp4TansmitCompletionToken;
EFI_UDP4_TRANSMIT_DATA Udp4TransmitData;
EFI_HANDLE Udp4ChildHandle = NULL;
EFI_UDP4_PROTOCOL *Udp4Protocol = NULL;
EFI_SERVICE_BINDING_PROTOCOL *Udp4ServiceBindingProtocol = NULL;
CHAR8 TxBuffer[] = "Hello Server!";
/*
Step 1: Locate the corresponding Service Binding Protocol, if there is more then 1 network interface gBS->LocateHandleBuffer should be used
*/
Status = gBS->LocateProtocol(
&gEfiUdp4ServiceBindingProtocolGuid,
NULL,
&Udp4ServiceBindingProtocol);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
/*
Step 2: Create a new UDP4 instance
*/
Status = Udp4ServiceBindingProtocol->CreateChild(
Udp4ServiceBindingProtocol,
&Udp4ChildHandle);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
Status = gBS->HandleProtocol(
Udp4ChildHandle,
&gEfiUdp4ProtocolGuid,
&Udp4Protocol);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
/*
Step 3: Prepare the UDP4 instance
*/
Udp4ConfigData.AcceptBroadcast = FALSE;
Udp4ConfigData.AcceptPromiscuous = FALSE;
Udp4ConfigData.AcceptAnyPort = FALSE;
Udp4ConfigData.AllowDuplicatePort = FALSE;
Udp4ConfigData.TimeToLive = 16;
Udp4ConfigData.TypeOfService = 0;
Udp4ConfigData.DoNotFragment = TRUE;
Udp4ConfigData.ReceiveTimeout = 0;
Udp4ConfigData.TransmitTimeout = 0;
// Change to TRUE and set the following fields to zero if DHCP is used
Udp4ConfigData.UseDefaultAddress = FALSE;
gBS->CopyMem(&Udp4ConfigData.StationAddress, &gLocalAddress, sizeof(Udp4ConfigData.StationAddress));
gBS->CopyMem(&Udp4ConfigData.SubnetMask, &gSubnetMask, sizeof(Udp4ConfigData.SubnetMask));
Udp4ConfigData.StationPort = gLocalPort;
gBS->CopyMem(&Udp4ConfigData.RemoteAddress, &gRemoteAddress, sizeof(Udp4ConfigData.RemoteAddress));
Udp4ConfigData.RemotePort = gRemotePort;
Status = Udp4Protocol->Configure(
Udp4Protocol,
&Udp4ConfigData);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
/*
Step 4: Send data and wait for completion
*/
Udp4TansmitCompletionToken.Status = EFI_SUCCESS;
Udp4TansmitCompletionToken.Event = NULL;
Status = gBS->CreateEvent(
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TransmitEventCallback,
NULL,
&(Udp4TansmitCompletionToken.Event));
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
Udp4TansmitCompletionToken.Packet.TxData = &Udp4TransmitData;
Udp4TransmitData.UdpSessionData = NULL;
gBS->SetMem(&Udp4TransmitData.GatewayAddress, sizeof(Udp4TransmitData.GatewayAddress), 0x00);
Udp4TransmitData.DataLength = sizeof(TxBuffer);
Udp4TransmitData.FragmentCount = 1;
Udp4TransmitData.FragmentTable[0].FragmentLength = Udp4TransmitData.DataLength;
Udp4TransmitData.FragmentTable[0].FragmentBuffer = TxBuffer;
gTransmitCompleteFlag = FALSE;
LOG("Sending data...\r\n");
Status = Udp4Protocol->Transmit(
Udp4Protocol,
&Udp4TansmitCompletionToken);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
Status = WaitForFlag(
&gTransmitCompleteFlag,
Udp4Protocol,
10);
if (EFI_ERROR(Status)) {
TRACE(EFI_TIMEOUT);
// Error handling
return EFI_TIMEOUT;
}
if (EFI_ERROR(Udp4TansmitCompletionToken.Status)) {
TRACE(Status);
// Error handling
return Status;
}
LOG("Data sent.\r\n");
/*
Step 5: Receive data
*/
Udp4ReceiveCompletionToken.Status = EFI_SUCCESS;
Udp4ReceiveCompletionToken.Event = NULL;
Status = gBS->CreateEvent(
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
ReceiveEventCallback,
NULL,
&(Udp4ReceiveCompletionToken.Event));
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
Udp4ReceiveCompletionToken.Packet.RxData = NULL;
gReceiveCompleteFlag = FALSE;
LOG("Receiving data...\r\n");
Status = Udp4Protocol->Receive(
Udp4Protocol,
&Udp4ReceiveCompletionToken);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
Status = WaitForFlag(
&gReceiveCompleteFlag,
Udp4Protocol,
10);
if (EFI_ERROR(Status)) {
TRACE(EFI_TIMEOUT);
// Error handling
return EFI_TIMEOUT;
}
if (EFI_ERROR(Udp4ReceiveCompletionToken.Status)) {
TRACE(Status);
// Error handling
return Status;
}
/*
Step 6: Process received data
*/
if (
Udp4ReceiveCompletionToken.Packet.RxData &&
Udp4ReceiveCompletionToken.Packet.RxData->FragmentCount > 0 &&
Udp4ReceiveCompletionToken.Packet.RxData->DataLength > 0) {
LOG("Received '%a'.\r\n",
Udp4ReceiveCompletionToken.Packet.RxData->FragmentTable[0].FragmentBuffer);
}
else {
LOG("Received an empty package.\r\n");
}
/*
Step 7: Cleanup
*/
if (
Udp4ReceiveCompletionToken.Packet.RxData &&
Udp4ReceiveCompletionToken.Packet.RxData->RecycleSignal) {
Status = gBS->SignalEvent(Udp4ReceiveCompletionToken.Packet.RxData->RecycleSignal);
if (EFI_ERROR(Udp4ReceiveCompletionToken.Status)) {
TRACE(Status);
// Error handling
return Status;
}
}
Status = Udp4ServiceBindingProtocol->DestroyChild(
Udp4ServiceBindingProtocol,
Udp4ChildHandle);
if (EFI_ERROR(Udp4ReceiveCompletionToken.Status)) {
TRACE(Status);
// Error handling
return Status;
}
return EFI_SUCCESS;
}

MiSimon
- 1,225
- 1
- 8
- 10
-
Thank you again! I’m going to contact you again to show you the ultimated work (if I’ll be able to finish it) – Raffaele Bertani Apr 13 '21 at 15:36
-
I keep getting these errors. Do you know why? In file included from /usr/include/efi/efi.h:57, from main.c:1: /usr/include/efi/efiudp.h:14:5: error: expected declaration specifiers or ‘...’ before ‘{’ token 14 | { 0x3ad9df29, 0x4501, 0x478d, {0xb1, 0xf8, 0x7f, 0x7f, 0xe7, 0x0e, 0x50, 0xf3} } – Raffaele Bertani Apr 15 '21 at 12:08