从 efi 应用程序发送 TCP 或 UDP 数据包
Send TCP or UDP packets from efi application
我想开发一个在 EFI shell 中从 startup.nsh 自动执行的应用程序。这个应用程序应该将原始字节发送到一个 ip 地址并接收一些回来。我到处寻找在我的代码中实现简单网络协议的解释和示例,但一无所获。有人可以使用 gnu_efi 库解释和展示代码示例吗?
这是一个如何使用 EDK2 发送和接收 UDP 数据包的示例,将其移植到 gnu-efi 应该是一个简单的任务,用 uefi_call_wrapper 包装所有 gBS->、gRT-> 和 protocolXY 调用.
更改全局值以匹配您的客户端和服务器。
#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;
}
我想开发一个在 EFI shell 中从 startup.nsh 自动执行的应用程序。这个应用程序应该将原始字节发送到一个 ip 地址并接收一些回来。我到处寻找在我的代码中实现简单网络协议的解释和示例,但一无所获。有人可以使用 gnu_efi 库解释和展示代码示例吗?
这是一个如何使用 EDK2 发送和接收 UDP 数据包的示例,将其移植到 gnu-efi 应该是一个简单的任务,用 uefi_call_wrapper 包装所有 gBS->、gRT-> 和 protocolXY 调用.
更改全局值以匹配您的客户端和服务器。
#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;
}