【UEFI基础】EDK网络框架(DHCP4)

DHCP4

DHCP4协议说明

DHCP是应用层的协议,DHCP报文是承载UDP上的高层协议报文,采用67(DHCP服务器)和68(DHCP客户端)两个端口号。

DHCP的全称是Dynamic Host Configuration Protocol,它的主要功能是实现自动设置IP地址、统一管理IP地址分管。

在这里插入图片描述

其工作原理:

在这里插入图片描述

DHCP报文格式如下:

在这里插入图片描述

各个参数的说明如下:

字段长度(字节)含义
Op1表示报文的类型:
1:客户端请求报文
2:服务器响应报文
Htype1表示硬件地址的类型。对于以太网,该类型的值为“1”。
Hlen1表示硬件地址的长度,单位是字节。对于以太网,该值为6。
Hops1跳数。客户端设置为0,也能被一个代理服务器设置。
Xid4事务ID,由客户端选择的一个随机数,被服务器和客户端用来在它们之间交流请求和响应,客户端用它对请求和应答进行匹配。
该ID由客户端设置并由服务器返回,为32位整数。
Secs2由客户端填充,表示从客户端开始获得IP地址或IP地址续借后所使用了的秒数。
Flags2此字段在BOOTP中保留未用,在DHCP中表示标志字段。
Flags字段格式:
0 15
+---------------------------------+
`
Ciaddr4客户端的IP地址。只有客户端是Bound、Renew、Rebinding状态,并且能响应ARP请求时,才能被填充。
Yiaddr4“你自己的”或客户端的IP地址。
Siaddr4表明DHCP协议流程的下一个阶段要使用的服务器的IP地址。
Giaddr4该字段表示第一个DHCP中继的IP地址(注意:不是地址池中定义的网关)。
当客户端发出DHCP请求时,如果服务器和客户端不在同一个网络中,那么第一个DHCP中继在转发这个DHCP请求报文时会把自己的IP地址填入此字段。
服务器会根据此字段来判断出网段地址,从而选择为用户分配地址的地址池。
服务器还会根据此地址将响应报文发送给此DHCP中继,再由DHCP中继将此报文转发给客户端。
若在到达DHCP服务器前经过了不止一个DHCP中继,那么第一个DHCP中继后的中继不会改变此字段,只是把Hops的数目加1。
Chaddr16该字段表示客户端的MAC地址,此字段与前面的“Hardware Type”和“Hardware Length”保持一致。当客户端发出DHCP请求时,将自己的硬件地址填入此字段。对于以太网,当“Hardware Type”和“Hardware Length”分别为“1”和“6”时,此字段必须填入6字节的以太网MAC地址。
Sname64该字段表示客户端获取配置信息的服务器名字。此字段由DHCP Server填写,是可选的。
如果填写,必须是一个以0结尾的字符串。
File128该字段表示客户端的启动配置文件名。此字段由DHCP Server填写,是可选的。
如果填写,必须是一个以0结尾的字符串。
Options可变该字段表示DHCP的选项字段,至少为312字节,格式为“代码+长度+数据”。
DHCP通过此字段包含了服务器分配给终端的配置信息,如网关IP地址,DNS服务器的IP地址,客户端可以使用IP地址的有效租期等信息。

对应到代码中的结构体:

#pragma pack(1)
///
/// EFI_DHCP4_PACKET defines the format of DHCPv4 packets. See RFC 2131 for more information.
///
typedef struct {UINT8               OpCode;UINT8               HwType;UINT8               HwAddrLen;UINT8               Hops;UINT32              Xid;UINT16              Seconds;UINT16              Reserved;EFI_IPv4_ADDRESS    ClientAddr;       ///< Client IP address from client.EFI_IPv4_ADDRESS    YourAddr;         ///< Client IP address from server.EFI_IPv4_ADDRESS    ServerAddr;       ///< IP address of next server in bootstrap.EFI_IPv4_ADDRESS    GatewayAddr;      ///< Relay agent IP address.UINT8               ClientHwAddr[16]; ///< Client hardware address.CHAR8               ServerName[64];CHAR8               BootFileName[128];
} EFI_DHCP4_HEADER;
#pragma pack()

DHCP4代码综述

DHCP4也是一个通用的网络协议,其实现在NetworkPkg\Dhcp4Dxe\Dhcp4Dxe.inf,这里首先需要看下它的入口:

EFI_STATUS
EFIAPI
Dhcp4DriverEntryPoint (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{return EfiLibInstallDriverBindingComponentName2 (ImageHandle,SystemTable,&gDhcp4DriverBinding,ImageHandle,&gDhcp4ComponentName,&gDhcp4ComponentName2);
}

仅仅是安装了gDhcp4DriverBinding

EFI_DRIVER_BINDING_PROTOCOL  gDhcp4DriverBinding = {Dhcp4DriverBindingSupported,Dhcp4DriverBindingStart,Dhcp4DriverBindingStop,0xa,NULL,NULL
};

DHCP4在UEFI网络协议栈中的关系图:

支持
提供
支持
支持
提供
支持
提供
提供
提供
支持
提供
提供
支持
支持
提供
提供
提供
支持
提供
提供
gEfiPciIoProtocolGuid
UNDI
gEfiNetworkInterfaceIdentifierProtocolGuid_31
gEfiDevicePathProtocolGuid
SNP
gEfiSimpleNetworkProtocolGuid
MNP
gEfiVlanConfigProtocolGuid
gEfiManagedNetworkServiceBindingProtocolGuid
gEfiManagedNetworkProtocolGuid
ARP
gEfiArpServiceBindingProtocolGuid
gEfiArpProtocolGuid
IP4
gEfiIp4ServiceBindingProtocolGuid
gEfiIp4Config2ProtocolGuid
gEfiIp4ProtocolGuid
DHCP4
gEfiDhcp4ServiceBindingProtocolGuid
gEfiDhcp4ProtocolGuid

它跟DNS4的结构基本一致。

Dhcp4DriverBindingSupported

DHCP4依赖于UDP4:

EFI_STATUS
EFIAPI
Dhcp4DriverBindingSupported (IN EFI_DRIVER_BINDING_PROTOCOL  *This,IN EFI_HANDLE                   ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL)
{Status = gBS->OpenProtocol (ControllerHandle,&gEfiUdp4ServiceBindingProtocolGuid,NULL,This->DriverBindingHandle,ControllerHandle,EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
}

Dhcp4DriverBindingStart

Start函数的流程大致如下:

  1. 创建DHCP_SERVICE,后面会进一步介绍。
  2. 通过UDP4来接收数据,对应的函数是UdpIoRecvDatagram(),该函数会循环执行:
EFI_STATUS
EFIAPI
UdpIoRecvDatagram (IN  UDP_IO           *UdpIo,IN  UDP_IO_CALLBACK  CallBack,IN  VOID             *Context,IN  UINT32           HeadLen)
{RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);UdpIo->RecvRequest = RxToken;if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);}
}

因为Start函数中有如下的代码:

  //// Start the receiving//Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);

所以UdpIoRecvDatagram()中创建的Token对应的回调函数是DhcpInput(),而该函数的实现中有:

VOID
EFIAPI
DhcpInput (NET_BUF        *UdpPacket,UDP_END_POINT  *EndPoint,EFI_STATUS     IoStatus,VOID           *Context)
{// 前面是数据处理,处理完之后就跳转到RESTRT,或者就走这里的异常,但是也是调用了UdpIoRecvDatagram()if (EFI_ERROR (Status)) {NetbufFree (UdpPacket);UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);DhcpEndSession (DhcpSb, Status);return;}RESTART:Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);
}

所以在注释中才有“Start the receiving”的说法。

  1. 安装gEfiDhcp4ServiceBindingProtocolGuid

DHCP_SERVICE

DHCP_SERVICE在Start函数中创建:

EFI_STATUS
EFIAPI
Dhcp4DriverBindingStart (IN EFI_DRIVER_BINDING_PROTOCOL  *This,IN EFI_HANDLE                   ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL)
{Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);
}

其结构体位于NetworkPkg\Dhcp4Dxe\Dhcp4Impl.h:

//
// DHCP driver is specical in that it is a singleton. Although it
// has a service binding, there can be only one active child.
//
struct _DHCP_SERVICE {UINT32                          Signature;EFI_SERVICE_BINDING_PROTOCOL    ServiceBinding;INTN                            ServiceState; // CONFIGED, UNCONFIGED, and DESTROYEFI_HANDLE                      Controller;EFI_HANDLE                      Image;LIST_ENTRY                      Children;UINTN                           NumChildren;INTN                            DhcpState;EFI_STATUS                      IoStatus;   // the result of last user operationUINT32                          Xid;IP4_ADDR                        ClientAddr; // lease IP or configured client addressIP4_ADDR                        Netmask;IP4_ADDR                        ServerAddr;EFI_DHCP4_PACKET                *LastOffer; // The last received offerEFI_DHCP4_PACKET                *Selected;DHCP_PARAMETER                  *Para;UINT32                          Lease;UINT32                          T1;UINT32                          T2;INTN                            ExtraRefresh; // This refresh is reqested by userUDP_IO                          *UdpIo;       // Udp child receiving all DHCP messageUDP_IO                          *LeaseIoPort; // Udp child with lease IPEFI_DHCP4_PACKET                *LastPacket;  // The last sent packet for retransmissionEFI_MAC_ADDRESS                 Mac;UINT8                           HwType;UINT8                           HwLen;UINT8                           ClientAddressSendOut[16];DHCP_PROTOCOL                   *ActiveChild;EFI_DHCP4_CONFIG_DATA           ActiveConfig;UINT32                          UserOptionLen;//// Timer event and various timer//EFI_EVENT                       Timer;UINT32                          PacketToLive; // Retransmission timer for our packetsUINT32                          LastTimeout;  // Record the init value of PacketToLive every timeINTN                            CurRetry;INTN                            MaxRetries;UINT32                          LeaseLife;
};

这里首先需要注意开头的注释,虽然可以由多个这样的服务数据,但是DHCP4只是一个单例(singleton),也就是有效的只有一个。

重要参数说明如下:

  • ServiceState:对应的值:
//
// The state of the DHCP service. It starts as UNCONFIGED. If
// and active child configures the service successfully, it
// goes to CONFIGED. If the active child configures NULL, it
// goes back to UNCONFIGED. It becomes DESTROY if it is (partly)
// destroyed.
//
#define DHCP_UNCONFIGED  0
#define DHCP_CONFIGED    1
#define DHCP_DESTROY     2

关于它的使用情况已经在上述注释总说明。

  • DhcpState:它表示的是通信过程中的DHCP状态,对应的值:
typedef enum {////// The EFI DHCPv4 Protocol driver is stopped.///Dhcp4Stopped = 0x0,////// The EFI DHCPv4 Protocol driver is inactive.///Dhcp4Init = 0x1,////// The EFI DHCPv4 Protocol driver is collecting DHCP offer packets from DHCP servers.///Dhcp4Selecting = 0x2,////// The EFI DHCPv4 Protocol driver has sent the request to the DHCP server and is waiting for a response.///Dhcp4Requesting = 0x3,////// The DHCP configuration has completed.///Dhcp4Bound = 0x4,////// The DHCP configuration is being renewed and another request has/// been sent out, but it has not received a response from the server yet.///Dhcp4Renewing = 0x5,////// The DHCP configuration has timed out and the EFI DHCPv4/// Protocol driver is trying to extend the lease time.///Dhcp4Rebinding = 0x6,////// The EFI DHCPv4 Protocol driver was initialized with a previously/// allocated or known IP address.///Dhcp4InitReboot = 0x7,////// The EFI DHCPv4 Protocol driver is seeking to reuse the previously/// allocated IP address by sending a request to the DHCP server.///Dhcp4Rebooting = 0x8
} EFI_DHCP4_STATE;
  • IoStatus:表示的是DHCP通信操作导致的状态。
  • Xid:一个随机数,在DHCP4协议说明中已经有介绍。
  • ClientAddrNetmaskServerAddrClientAddr是通过DHCP租用到的IP地址,对应代码:
EFI_STATUS
DhcpLeaseAcquired (IN OUT DHCP_SERVICE  *DhcpSb)
{DhcpSb->ClientAddr = EFI_NTOHL (DhcpSb->Selected->Dhcp4.Header.YourAddr);if (DhcpSb->Para != NULL) {DhcpSb->Netmask    = DhcpSb->Para->NetMask;DhcpSb->ServerAddr = DhcpSb->Para->ServerId;}
}

另外两个IP也在这里设置。

  • LastOffer:最后一次收到的包。
  • Selected:从中获取IP的那个包。
  • Para:DHCP参数,其结构体如下:
///
/// The options that matters to DHCP driver itself. The user of
/// DHCP clients may be interested in other options, such as
/// classless route, who can parse the DHCP offer to get them.
///
typedef struct {IP4_ADDR    NetMask;                // DHCP4_TAG_NETMASKIP4_ADDR    Router;                 // DHCP4_TAG_ROUTER, only the first router is used//// DHCP specific options//UINT8       DhcpType;               // DHCP4_TAG_MSG_TYPEUINT8       Overload;               // DHCP4_TAG_OVERLOADIP4_ADDR    ServerId;               // DHCP4_TAG_SERVER_IDUINT32      Lease;                  // DHCP4_TAG_LEASEUINT32      T1;                     // DHCP4_TAG_T1UINT32      T2;                     // DHCP4_TAG_T2
} DHCP_PARAMETER;

LeaseT1T2等参数也在这里有体现。

  • ExtraRefresh:更新租用期时会使用到,对应到函数:
/**Extends the lease time by sending a request packet.The RenewRebind() function is used to manually extend the lease time when theEFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time hasnot expired yet. This function will send a request packet to the previouslyfound server (or to any server when RebindRequest is TRUE) and transfer thestate into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest isTRUE). When a response is received, the state is returned to Dhcp4Bound.If no response is received before the try count is exceeded (the RequestTryCountfield that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time thatwas issued by the previous server expires, the driver will return to the Dhcp4Boundstate and the previous configuration is restored. The outgoing and incoming packetscan be captured by the EFI_DHCP4_CALLBACK function.@param[in]  This            Pointer to the EFI_DHCP4_PROTOCOL instance.@param[in]  RebindRequest   If TRUE, this function broadcasts the request packets and entersthe Dhcp4Rebinding state. Otherwise, it sends a unicastrequest packet and enters the Dhcp4Renewing state.@param[in]  CompletionEvent If not NULL, this event is signaled when the renew/rebind phasecompletes or some error occurs.EFI_DHCP4_PROTOCOL.GetModeData() can be called tocheck the completion status. If NULL,EFI_DHCP4_PROTOCOL.RenewRebind() will busy-waituntil the DHCP process finishes.@retval EFI_SUCCESS           The EFI DHCPv4 Protocol driver is now in theDhcp4Renewing state or is back to the Dhcp4Bound state.@retval EFI_NOT_STARTED       The EFI DHCPv4 Protocol driver is in the Dhcp4Stoppedstate. EFI_DHCP4_PROTOCOL.Configure() needs tobe called.@retval EFI_INVALID_PARAMETER This is NULL.@retval EFI_TIMEOUT           There was no response from the server when the try count wasexceeded.@retval EFI_ACCESS_DENIED     The driver is not in the Dhcp4Bound state.@retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.**/
EFI_STATUS
EFIAPI
EfiDhcp4RenewRebind (IN EFI_DHCP4_PROTOCOL  *This,IN BOOLEAN             RebindRequest,IN EFI_EVENT           CompletionEvent   OPTIONAL)
{DhcpSb->ExtraRefresh       = TRUE;
}
  • UdpIo:UDP4通信接口,这里包装了一层,因为有v4和v6两个版本,我们只关注v4版本。
  • LeaseIoPort:也是UDP4通信接口,不过对应到获取租用IP的接口。
  • LastPacket:最后发送的包。
  • MacHwTypeHwLen:网卡参数,对应到EFI_SIMPLE_NETWORK_MODE中的值。
  • ClientAddressSendOut:对应DHCP包头部中的ClientHwAddr
  • ActiveChildActiveConfig:前面已经说过DHCP使用单例,所以对应的DHCP_PROTOCOL也只有一个是有效的,这个就执行有效的DHCP_PROTOCOL,以及对应的参数。
  • UserOptionLen:DHCP选项的长度。
  • Timer:一个定时器,在创建服务时创建:
  //// Create various resources, UdpIo, Timer, and get Mac address//Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL | EVT_TIMER,TPL_CALLBACK,DhcpOnTimerTick,DhcpSb,&DhcpSb->Timer);

从对应的回调函数中可以知道它的作用:

/**Each DHCP service has three timer. Two of them are count down timer.One for the packet retransmission. The other is to collect the offers.The third timer increments the lease life which is compared to T1, T2,and lease to determine the time to renew and rebind the lease.DhcpOnTimerTick will be called once every second.@param[in]  Event                 The timer event@param[in]  Context               The context, which is the DHCP service instance.**/
VOID
EFIAPI
DhcpOnTimerTick (IN EFI_EVENT  Event,IN VOID       *Context)

它每秒执行一次:

  Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
  • PacketToLiveLastTimeoutCurRetryMaxRetries:与定时器相关的一些值,还与重发等机制相关。
  • LeaseLife:租用时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/419172.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字节跳动 ByteHouse 云原生之路 – 计算存储分离与性能优化

01 起源 ByteHouse 的故事从字节跳动对于先进数据处理和分析的需求开始&#xff0c;这一需求随着公司业务规模的迅速扩张而日益增长&#xff0c;起源是对开源数据库管理系统 ClickHouse 的改造和增强。面对数据处理的高延迟、大规模数据操作的复杂性以及数据存储和处理成本的上…

【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL&#xff08;输入/输出控制&#xff09;或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。 一、IOCTL 方法 1. 定义IOCTL命令 在内核模块中&#xff0c;需要使用宏定义你的IOCTL命令。通常情况下&#xff0c;IOCTL命令…

实战内网穿透NPS搭建过程

前提条件 首先你要有个公网IP的服务器&#xff0c;既然是内网穿透&#xff0c;那必然是通过公网IP或者域名访问本地服务。 官网下载地址 https://github.com/ehang-io/nps/releases 服务端 选择linux_amd64_server.tar.gz 客户端 选择windows_amd64_client.tar.gz 服…

EasyRecovery2024电脑数据恢复工具好不好用?

Ontrack是我们综述中的第一个产品&#xff0c;由于该软件的功效和广度&#xff0c;我认为它完全基于业务。有一个具有基本功能的免费版本和一系列付费版本&#xff0c;不仅可以恢复文件&#xff08;免费版和家庭版&#xff09;&#xff0c;还可以创建磁盘映像/从 CD 和 DVD 恢复…

统计学-R语言-7.1

文章目录 前言假设检验的原理假设检验的原理提出假设做出决策表述结果效应量 总体均值的检验总体均值的检验(一个总体均值的检验) 练习 前言 本章主题是假设检验(hypothesis testing)。与参数估计一样&#xff0c;假设检验也是对总体参数感兴趣&#xff0c;如比例、比例间的差…

【PyTorch】在PyTorch中使用线性层和交叉熵损失函数进行数据分类

在PyTorch中使用线性层和交叉熵损失函数进行数据分类 前言&#xff1a; 在机器学习的众多任务中&#xff0c;分类问题无疑是最基础也是最重要的一环。本文将介绍如何在PyTorch框架下&#xff0c;使用线性层和交叉熵损失函数来解决分类问题。我们将以简单的Iris数据集作为起点…

数组中第K个最大元素(算法村第十关白银挑战)

215. 数组中的第K个最大元素 - 力扣&#xff08;LeetCode&#xff09; 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 **k** 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现…

JVM工作原理与实战(二十一):内存管理

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、不同语言的内存管理 1.C/C的内存管理 2.Java的内存管理 二、垃圾回收的对比 1.自动垃圾回收与手动垃圾回收的对比 2.优点与缺点 总结 前言 JVM作为Java程序的运行环境&#…

Golang 搭建 WebSocket 应用(八) - 完整代码

本文应该是本系列文章最后一篇了&#xff0c;前面留下的一些坑可能后面会再补充一下&#xff0c;但不在本系列文章中了。 整体架构 再来回顾一下我们的整体架构&#xff1a; 在我们的 demo 中&#xff0c;包含了以下几种角色&#xff1a; 客户端&#xff1a;一般是浏览器&am…

XSS漏洞:利用多次提交技巧实现存储型XSS

目录 搭建环境 XSS攻击 测试 xss系列往期文章&#xff1a; 初识XSS漏洞-CSDN博客 利用XSS漏洞打cookie-CSDN博客 XSS漏洞&#xff1a;xss-labs靶场通关-CSDN博客 XSS漏洞&#xff1a;prompt.mi靶场通关-CSDN博客 XSS漏洞&#xff1a;xss.haozi.me靶场通关-CSDN博客 本…

磁盘分区机制

lsblk查看分区 Linux分区 挂载的经典案例 1. 虚拟机增加磁盘 点击这里&#xff0c;看我的这篇文章操作 添加之后&#xff0c;需要重启系统&#xff0c;不重启在系统里看不到新硬盘哦 出来了&#xff0c;但还没有分区 2. 分区 还没有格式化 3. 格式化磁盘 4. 挂载 5. 卸载…

汇编语言----X86汇编指令

目录 1.汇编指令的构成 2.X86架构CPU中包含的寄存器 3.常见的x86汇编指令 &#xff08;1&#xff09;算数运算 &#xff08;2&#xff09;逻辑运算 &#xff08;3&#xff09;其他 4.AT&T格式 5.选择语句&#xff08;分支结构&#xff09; 6.循环语句 &#xff0…