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

2024-01-08

我想开发一个在 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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 efi 应用程序发送 TCP 或 UDP 数据包 的相关文章

  • UEFI启动,安装CentOS7报错tsc: Fast TSC calibration failed

    安装CentOS7系统报错 tsc Fast TSC calibration failed 多的不说 xff0c 选择Boot启动时有 USB SanDisk和UEFI xff1a SanDisk xff0c Partition 4 xff
  • 解决微PE不支持移动硬盘NTFS的UEFI启动

    众所周知 FAT32格式硬盘不支持大于4G的单个文件 于是我在用移动硬盘做启动盘时 想用NTFS 但是PE工具箱又提示如下信息 xff1a 开始想办法处理 xff1a 一 硬盘单独分一个区出来做fat32格式 用作UEFI启动 失败 微PE
  • 详写 UEFI & BIOS 安装 Arch Linux

    Arch Linux官方安装向导 xff1a https wiki archlinux org index php Installation guide 文章目录 1 准备2 VirtualBox 打开 EFI3 安装验证启动方式连接互联网
  • VMWare Workstation 使用UEFI启动

    创建新的虚拟机编辑虚拟机所在目录 VMX 增加一行 span class token assign left variable firmware span span class token operator 61 span span cla
  • bios uefi 区别_UEFI vs BIOS:有何区别?

    bios uefi 区别 So you might have heard the acronyms BIOS and UEFI thrown around especially when trying to switch Operating
  • 树莓派4B构建debian镜像UEFI启动

    树莓派4B构建debian镜像UEFI启动 前言 今天按照大佬的博客树莓派俱乐部官方 Debian 系统镜像 支持UEFI跑了遍 完整的UEFI镜像构建过程 包括镜像分区 挂载 xff0c 根文件系统的制作 xff0c 内核的移植 xff0
  • win10+中标麒麟双系统安装步骤

    win7 10 中标麒麟双系统安装步骤 场景要求 联想启天M415台机出厂预装的是win10 现在要改成win7和中标麒麟7 0双系统 开机在选择系统界面要有两个系统选择 并且默认进入win7 注 先安装win7 再安装中标麒麟 一开始是用
  • Win10+Ubuntu16.04双系统重装win10后ubuntu引导失败UEFI启动方式下GRUB消失

    参考博客 http blog csdn net zrf2112 article details 71042782 参考文章 https wiki deepin org index php title E4 BF AE E5 A4 8D E5
  • UEFI启动U盘制作

    说明 在网上搜索了一下UEFI启动U盘工具 发现都是一些超级大的工具 动不动就是上百兆 而且之前使用老毛桃安装系统 发现会在系统中安装很多其他的软件 心有余悸 所以打算找一个干净的工具 随后在网上搜索找到rufus 使用 下载rufus h
  • UEFI-SHELL 环境 U盘制作

    访问 https github com pbatard UEFI Shell releases 下载最新的ISO 然后用rufus 做启动盘 Rufus https rufus ie en map list device DUMP BIOS
  • UEFI与BIOS(CSM)下安装Windows以及双系统需要知道的一些事

    文章目录 EFI是什么 CSM是什么 UEFI是什么 安装Windows时需要注意什么 安装双系统时需要注意什么 参考 EFI是什么 我之前的一篇博客计算机启动的基本过程提到了BIOS是个程序 存储在BIOS芯片中 而现在的新式电脑用的基本
  • Docker Compose 配置文件 docker-compose.yml 详解

    Docker Compose配置文件是Docker Compose的核心 用于定义服务 网络和数据卷 格式为YAML 默认路径为 docker compose yml 可以使用 yml或 yaml扩展名 目前Compose配置文件格式的最新
  • 【Linux】【Ubuntu】在VMware虚拟机中安装Ubuntu18.04(UEFI启动图文教程)

    在VMware虚拟机中安装Ubuntu18 04 以UEFI方式启动 VMware 版本 15 5 以UEFI启动的Ubuntu系统安装方式与 Linux Ubuntu 在VMware虚拟机中安装Ubuntu18 04 保姆级图文教程 中记
  • 我可以使用 EFI 在本地文件系统上写入吗

    我正在开发这个项目 以便在操作系统通过 EFI 应用程序启动后立即将文件写入本地文件系统 我需要知道是否可能 如果是的话 请指导我一点 谢谢 好吧 我会好好提醒你的 首先枚举系统中的所有 FS 协议 EFI BOOT SERVICES bs
  • 启动时自动运行 EFI 应用程序

    I can 构建并手动执行 http sourceforge net apps mediawiki tianocore index php title Getting Started Writing Simple ApplicationUE
  • UEFI引导加载程序

    我正在考虑开发一个简单的 首先 UEFI 引导加载程序来加载 ELF 映像 并且想知道是否有人有一个很好的切入点 可以进入任何现有项目 或者我可以用来开始使用的示例 另外 我想知道是否有人有让虚拟机运行 EFI 应用程序的经验 我已经设置了
  • 在内核模式下读取/写入 Linux 上的 EFI 变量

    我正在研究 Linux UEFI 我想通过我的驱动程序代码访问 efi 变量 目前我正在寻找像 efi get variable 这样的 linux efi h API 但我不知道如何从我的驱动程序代码中调用这些 API struct ef
  • 从 efi 应用程序发送 TCP 或 UDP 数据包

    我想开发一个在 EFI shell 中从startup nsh 自动执行的应用程序 此应用程序应将原始字节发送到 IP 地址并接收一些返回的字节 我到处寻找在我的代码中实现简单网络协议的解释和示例 但一无所获 有人可以解释并显示使用 gnu
  • 如何在启动操作系统之前进行一些安全验证?

    我有一个可启动闪存盘 其中包含定制的 Ubunto 我想将闪存盘传递给未知的人 但它存在一些安全问题 我想确保未知的人无法更改闪存盘内容 因此 我想计算闪存内容的哈希值并在每次启动时验证它 并在验证失败或哈希不匹配时防止启动操作系统 为此
  • 使用 Visual Studio 构建 UEFI 驱动程序

    我正在寻找有关如何使用 Visual Studio 2012 项目通过 EDK2 SDK 构建 UEFI 驱动程序的建议 我试图静态链接 UefiLib lib 但惨败 我已将该库添加到链接器下的附加依赖项中 include

随机推荐

  • ListView距列表顶部的距离

    我有一个ListView 我想制作一个随列表滚动的背景 我看到了代码Shelves http code google com p shelves source browse trunk Shelves src org curiouscrea
  • 从vba中的write语句中删除双引号

    此代码将日志文件写入 LogFilePath 并生成如下输出 StarRange 和 EndRange 是一个变量 其值将从其他函数填充 Start postion A1 End position B100 Code Sub WriteLo
  • SVN:递归添加

    我正在尝试从我的工作副本中的 SVN 文件夹中添加新的项目文件 它询问选项 递归 并显示消息 您确定要添加 许多项目 有人可以指导我启用此 递归 选项有什么用吗 当我新添加新项目文件时我是否应该启用它 谢谢 简洁版本 svn add for
  • 如何用ggplot对齐两个图?

    我试图使用对齐两个图grid但没有成功 我尝试调整主题 使绘图边框 大小相同 但尽管使用相同的 y 坐标 但绘图并未对齐 对于下面的例子我可以使用annotation custom 网站上有一些示例 但这限制了我可以添加的文本数量 如有任何
  • Visual Studio 2015 无法启动

    我们已经在 Windows 7 上安装了 Visual Studio 2015 Professional 它运行良好 但是今天我们从菜单 工具 gt 扩展和更新 安装更新后 Visual Studio 不再启动 我们也尝试使用 以管理员身份
  • Asp .Net Core Web API 在哪里订阅 RabbitMQ

    我正在尝试使用 Web API 和 Rabbit MQ 消息代理来实现发布 订阅架构 我的解决方案中有两个项目 发布者和订阅者 发布正在成功实施 但我在我的网站中找不到位置 订阅者项目从队列中读取已发布的消息 我的两个项目都是 Net Co
  • 从 XML 数据反序列化数组(在 ServiceStack 中)

    我有以下 XML 数据块
  • 使用钩子检测 React 组件外部的点击

    我发现我正在跨应用程序重用行为 当用户单击元素外部时我可以隐藏它 随着钩子的引入 我是否可以将其放入钩子中并在组件之间共享 以节省我在每个组件中编写相同的逻辑 我已经在组件中实现了一次 如下所示 const Dropdown gt cons
  • Bootstrap 表 - 如何访问数据源对象中的内部元素

    假设我的数据源对象看起来像这样 id 123 name blabla1 kids id kid1 name kk1 id 456 name blabla2 kids id kid2 name kk2 这是一个包含 2 个对象的列表 数组 每
  • Java 9:在 Eclipse 中无法访问模块 java.xml.bind

    我将 Maven 项目迁移到Java 8 to a Java 9没有任何构建工具的项目Eclipse OxyGen 1a So my 模块信息 java看起来像这样 但是 java xml bind 无法访问 尽管它在我的模块路径中 那么这
  • 将基于 Java 的 API 与 Django 结合使用

    我正在使用 Django 创建一个网站 并希望将 Google Play 商店 Android Market 中的数据合并到其中 我考虑过手动抓取商店 但看起来这可能是一个缓慢而乏味的过程 所以我决定考虑其他选项 即一个名为android
  • 将 /var/run/docker.sock 挂载到容器中时,使用哪个文件系统进行卷挂载?

    我有一个容器 其中包含用于协调主机上微服务部署的逻辑 让我们将此服务称为deployer 为了实现这一目标 我安装了 var run docker sock文件从主机到那个deployer容器 所以 表演的时候docker run hell
  • Spring BeanPostProcessor 究竟是如何工作的?

    我正在学习 Spring Core 认证 我对 Spring 如何处理这些问题有一些疑问Bean 生命周期特别是关于Bean 后处理器 所以我有这个架构 我很清楚这意味着什么 以下步骤发生在加载 Bean 定义 phase The 配置类被
  • 如何在 Visual Studio 2008“Pro”中进行性能分析

    微软将这款软件称为 Visual Studio 2008 Professional 我发现其中似乎没有应用程序性能分析器或类似的东西 这使得它对我来说似乎不那么 专业 如果 Microsoft 不包含分析器 您有哪些第三方选项可以用于 Vi
  • 数据仓库中的时间和日期维度

    I m building a data warehouse Each fact has it s timestamp I need to create reports by day month quarter but by hours to
  • 如何分配线程来处理 Servlet 请求?

    有人可以解释一下什么是每个请求线程和每个连接线程吗 servlet 适用于哪种模型 如何分配线程来处理 HTTP 请求 是线程 请求还是连接 假设我想在我的计算机中执行一项耗时的任务Servlet s doGet 方法异步 我使用 Java
  • 无需预处理器即可扩展 C/C++ 函数宏

    如何在 C C 文件中测试 扩展所有函数宏 而不通过预处理器运行它 例如 是否有一个程序或方法可以改变这一点 include
  • PHP服务器ERR_CONNECTION_REFUSED

    我无法让 php 服务器在我的本地计算机上运行 我尝试使用 wampserver 和 Easy PHP 我检查了我的使用情况port 80 我更改了端口 80 to 8080 我给了 Apache 和 mysql 防火墙设置所需的权限 我做
  • 在 WPF 中将窗口的 DataContext 绑定到窗口本身

    我有一个继承自 Window 的简单对话框窗口 我在 XAML 中设置它的 DataContext 如下所示
  • 从 efi 应用程序发送 TCP 或 UDP 数据包

    我想开发一个在 EFI shell 中从startup nsh 自动执行的应用程序 此应用程序应将原始字节发送到 IP 地址并接收一些返回的字节 我到处寻找在我的代码中实现简单网络协议的解释和示例 但一无所获 有人可以解释并显示使用 gnu