Я хочу разработать приложение для автоматического запуска из startup.nsh в оболочке EFI. Это приложение должно отправлять необработанные байты на IP-адрес и получать обратно. Я везде искал объяснение и пример реализации простого сетевого протокола в моем коде, но ничего не нашел. Может ли кто-нибудь объяснить и показать пример кода с использованием библиотек gnu_efi?
Отправка пакетов TCP или UDP из приложения efi
comment
Спецификация UEFI содержит полный пример использования протокола HTTP. Шаги почти одинаковы для UDP и TCP (вызовите Connect перед отправкой каких-либо данных, если вы используете TCP).
- person MiSimon   schedule 12.04.2021
comment
Мне не нужно использовать протокол http, просто простой сетевой протокол для отправки простого символа и получения его обратно. Я читал о протоколе дескриптора, но я не могу понять, как на самом деле реализовать все эти вещи вместе.
- person Raffaele Bertani   schedule 13.04.2021
comment
В заголовке указано, что для TCP или UDP вам нужен протокол TCPv4 или UDP, SNP (простой сетевой протокол) не следует использовать напрямую, вместо этого вы должны использовать MNP. Но вы можете отправлять необработанные пакеты только с SNP или MNP.
- person MiSimon   schedule 13.04.2021
comment
Большое спасибо. Этот ПРОТОКОЛ UDPv4 выглядит как решение. Но главная проблема остается прежней. Не могли бы вы или кто-нибудь привести несколько строк примера отправки символа «S» на x.y.w.z:33333?
- person Raffaele Bertani   schedule 13.04.2021
comment
Я могу предоставить вам простой пример на основе EDK2, вам просто нужно использовать uefi_call_wrapper вокруг каждого метода UEFI, чтобы заставить его работать с gnu-efi.
- person MiSimon   schedule 13.04.2021
comment
stackoverflow.com/ questions/67073808/ Этот вопрос лучше объясняет мою ситуацию. Большое спасибо
- person Raffaele Bertani   schedule 13.04.2021
comment
@MiSimon здесь ошибка main.c: 284: 58: ошибка: запрос члена «DestroyChild» в чем-то, что не является структурой или союзом 284 | Status = uefi_call_wrapper(Udp4ServiceBindingProtocol->DestroyChild,2,Udp4ServiceBindingProtocol,Udp4ChildHandle);
- person Raffaele Bertani   schedule 15.04.2021
comment
Пожалуйста, создайте проект на github (или аналогичный) и опубликуйте ссылку.
- person MiSimon   schedule 15.04.2021
comment
Я забыл InitializeLib. Сегодня вечером я попробую еще раз, если это все еще не сработает, я создам GitHub
- person Raffaele Bertani   schedule 15.04.2021
comment
@MiSimon, вот мой проект: github.com/RapRaf/AlexaBootEFI
- person Raffaele Bertani   schedule 15.04.2021
comment
@MiSimon извините, ничего не отправляет. Он выполняется и завершается, не дождавшись ответа. Нет ошибок, но нет пакетов, отправленных из приложения efi. Что бы это могло быть?
- person Raffaele Bertani   schedule 20.04.2021
Ответы (1)
Вот пример того, как отправлять и получать пакеты UDP с помощью EDK2, перенос его на gnu-efi должен быть простой задачей, оберните все вызовы gBS-›, gRT-› и protocolXY с помощью uefi_call_wrapper.
Измените глобальные значения, чтобы они соответствовали вашему клиенту и серверу.
#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;
}
person
MiSimon
schedule
13.04.2021
Еще раз спасибо! Я свяжусь с вами снова, чтобы показать вам окончательную работу (если я смогу ее закончить)
- person Raffaele Bertani; 13.04.2021
Я продолжаю получать эти ошибки. Ты знаешь почему? В файле, включенном из /usr/include/efi/efi.h:57, из main.c:1: /usr/include/efi/efiudp.h:14:5: ошибка: ожидаемые спецификаторы объявления или '...' перед токеном '{' 14 | { 0x3ad9df29, 0x4501, 0x478d, {0xb1, 0xf8, 0x7f, 0x7f, 0xe7, 0x0e, 0x50, 0xf3} }
- person Raffaele Bertani; 15.04.2021