从efi应用程序发送TCP或UDP数据包



我想开发一个在EFI shell中从startup.nsh自动执行的应用程序。这个应用程序应该将原始字节发送到一个ip地址,并接收一些返回。我到处寻找代码中简单网络协议实现的解释和示例,但一无所获。有人能解释并展示一个使用gnuefi库的代码示例吗?

下面是一个如何使用EDK2发送和接收UDP数据包的示例,将其移植到gnu efi应该是一项简单的任务,包装所有gBS->,gRT->以及与uefi_call_wrapper的protocolXY调用。

更改全局值以匹配您的客户端和服务器。

#include <Uefi.h>
#include <LibraryUefiLib.h>
#include <ProtocolServiceBinding.h>
#include <ProtocolUdp4.h>
#include <ProtocolSimpleNetwork.h>
#include <ProtocolManagedNetwork.h>
#include <ProtocolIp4.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'rn", 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...rn");
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.rn");

/*
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...rn");
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'.rn", 
Udp4ReceiveCompletionToken.Packet.RxData->FragmentTable[0].FragmentBuffer);
}
else {
LOG("Received an empty package.rn");
}

/*
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;
}

相关内容

  • 没有找到相关文章

最新更新