从 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 数据包 的相关文章

  • 服务器修改bios中uefi,浅谈UEFI~BIOS,申精。

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 UEFI 启动管理器 UEFI 规范定义了名为 UEFI 启动管理器的一项功能 Linux发行版包含名为efibootmgr 的工具 xff0c 可用于更改 UEFI 启动管理器的配置 如果你确
  • 解决微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
  • uefi和legacy bios的深度剖析

    这个是我总结的 参考了几个论坛还有 鸟哥的私房菜 还有一部分是我自己的经验 适合初步了解uefi和legacy的人更深入的了解 uefi amp legacy Legacy 1 我们可将MBR磁盘分区结构用下图简单表示 xff08 Wind
  • 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
  • UEFI模式下双系统安装并引导启动注意事项(RHLE7.9&WIN10)

    UEFI模式下双系统安装并引导启动注意事项 xff08 RHLE7 9 amp WIN10 xff09 引言新的改变资源链接注意事项 引言 就如同大佬说的一样 xff0c 知识也是需要与时俱进的 xff0c 在技术高速革新的时代 xff0c
  • 树莓派4B构建debian镜像UEFI启动

    树莓派4B构建debian镜像UEFI启动 前言 今天按照大佬的博客树莓派俱乐部官方 Debian 系统镜像 支持UEFI跑了遍 完整的UEFI镜像构建过程 包括镜像分区 挂载 xff0c 根文件系统的制作 xff0c 内核的移植 xff0
  • css样式兼容、注释_CSS中的伪注释(或者,浏览器如何解析样式)

    css样式兼容 注释 The CSS spec does not mention it but you can mimic C style and or Unix style line comments in CSS files with
  • 日志收集-elk

    04 4 日志收集 1 日志收集方式 Kubernetes的业务Pod日志有两种输出方式 一种是直接打到标准输出或者标准错误 第二种是将日志写到特定目录下的文件种 针对这两种不同场景 提供了不同的容器日志收集思路 1 1 Kubernete
  • 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芯片中 而现在的新式电脑用的基本
  • UEFI基本概念

    TianoCore UEFI EDK2 UEFI Unified Extensible Firmware Interface 用来取代BIOS TianoCore 一个社区 支持UEFI的开源实现 EDK2 一种UEFI的开发环境 UEFI
  • 梳理Vue常考面试题型

    完整版在线阅读 http interview poetries top 1 对于MVVM的理解 MVVM是Model View ViewModel缩写 也就是把MVC中的Controller演变成ViewModel Model层代表数据模型
  • 利用外部程序对存储BIOS设置参数的CMOS RAM进行读取操作的可行性分析

    电脑的启动过程如下 机后主动执行BIOS程序 可以通过BIOS去设置CMOS 也可以不设置 然后BOIS会去识别操作系统引导设备的引导分区 一般也就是电脑里的硬盘中的第一个扇区 这个扇区中有分区表和主引导分区MBR 我们找到了MBR MBR
  • 我可以使用 EFI 在本地文件系统上写入吗

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

    我早些时候发布了这个问题超级用户但我觉得它更适合程序员 如果我理解正确的话 根据 GPT LBA 2 的前 16 个字节是磁盘上第一个分区的分区类型 GUID 在 Windows 磁盘管理中 第一个分区被指定为 EFI 系统分区 然而 经过
  • 从 efi 应用程序发送 TCP 或 UDP 数据包

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

    我正在使用 Visual Studio 2015 C C 编译器编译一段 UEFI C 代码 编译器的目标是IA32 不是 X64 当使用 O1 打开优化时 构建正常 When 关闭使用 Od 优化 构建给出以下错误 error LNK20

随机推荐

  • 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