tcpip.sys 传输层 (UDP) 详细分析
目录
- 概述
- [UDP 层整体架构](#UDP 层整体架构)
- [UDP 报文格式](#UDP 报文格式)
- [UDP 校验和](#UDP 校验和)
- 端口管理
- [UDP 子系统初始化](#UDP 子系统初始化)
- [UDP 发送路径](#UDP 发送路径)
- [UDP 接收路径](#UDP 接收路径)
- 数据报基础设施 (datagram.c)
- 数据投递逻辑 (DGDeliverData)
- 工作流程图
- 数据流图
- 关键函数索引
1. 概述
UDP (User Datagram Protocol,用户数据报协议) 是 TCP/IP 协议栈的传输层协议之一,提供无连接、不可靠的数据报传输服务。与 TCP 相比,UDP 没有连接建立、流量控制、拥塞控制、可靠交付等机制,但开销小、延迟低,适合 DNS、DHCP、流媒体等应用。
在 ReactOS tcpip.sys 中,UDP 位于传输层,通过 TDI 接口向上层提供服务,通过 IP 层发送/接收数据报。
1.1 架构定位
┌─────────────────────────────────────────────┐
│ 上层 (Winsock → AFD → TDI) │
│ TDI_SEND_DATAGRAM / TDI_RECEIVE_DATAGRAM │
└──────────────────┬──────────────────────────┘
│ tcpip.sys 内部
┌──────────────────▼──────────────────────────┐
│ 传输层 ←★ │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ UDP 模块 (udp.c) │ │
│ │ ├─ UDPSendDatagram (发送) │ │
│ │ ├─ UDPReceive (接收) │ │
│ │ ├─ BuildUDPPacket (构造报文) │ │
│ │ ├─ AddUDPHeaderIPv4 (加头) │ │
│ │ └─ UDPPorts (端口分配) │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ┌──────────────────▼────────────────────┐ │
│ │ 数据报基础设施 (datagram.c) │ │
│ │ ├─ DGReceiveDatagram (接收请求) │ │
│ │ ├─ DGDeliverData (数据投递) │ │
│ │ └─ DGRemoveIRP (取消请求) │ │
│ └───────────────────────────────────────┘ │
└──────────────────┬──────────────────────────┘
│ IPRegisterProtocol(IPPROTO_UDP, UDPReceive)
│ IPSendDatagram / IPReceive
┌──────────────────▼──────────────────────────┐
│ IP 网络层 │
└─────────────────────────────────────────────┘
1.2 UDP 的特点
| 特性 | UDP | TCP |
|---|---|---|
| 连接 | 无连接 | 面向连接 |
| 可靠性 | 不可靠 | 可靠 (确认/重传) |
| 有序性 | 无序 | 有序 |
| 流量控制 | 无 | 滑动窗口 |
| 拥塞控制 | 无 | 慢启动/拥塞避免 |
| 报文边界 | 保留 | 字节流 |
| 开销 | 8 字节头 | 20 字节头 |
| 应用 | DNS/DHCP/流媒体 | Web/邮件/文件传输 |
1.3 源码文件
| 源文件 | 职责 |
|---|---|
ip/transport/udp/udp.c |
UDP 报文构造、发送、接收 |
ip/transport/datagram/datagram.c |
数据报通用收发基础设施 |
include/udp.h |
UDP 头、伪头、统计结构定义 |
ip/transport/rawip/rawip.c |
Raw IP(复用数据报基础设施) |
2. UDP 层整体架构
2.1 发送路径
上层 (TDI_SEND_DATAGRAM)
│
▼
DispTdiSendDatagram → (*AddrFile->Send)(...)
│
└─ AddrFile->Send = UDPSendDatagram (绑定地址时设置)
│
▼
UDPSendDatagram(AddrFile, ConnInfo, BufferData, DataSize, DataUsed)
│
├─ 解析远端地址 (TDI_ADDRESS_TYPE_IP → IP_ADDRESS)
├─ 确定本地地址:
│ ├─ 未指定 → RouteGetRouteToDestination → 接口单播地址
│ └─ 已指定 → NBLocateNeighbor
│
├─ BuildUDPPacket → 构造 UDP 报文
│ └─ AddUDPHeaderIPv4 → AddGenericHeaderIPv4 + UDP 头填充
│
└─ IPSendDatagram(&Packet, NCE) ← 交给 IP 层
└─ 路由 → 分片 → 邻居 → 接口层
2.2 接收路径
IP 层 → IPDispatchProtocol(IF, IPPacket)
│
▼
UDPReceive(Interface, IPPacket) (ProtocolTable[17] 注册)
│
├─ 解析 IP/UDP 头
├─ 校验 UDP 校验和
├─ 数据区域定位 (跳过 UDP 头)
│
├─ AddrSearchFirst(DstAddress, DestPort, IPPROTO_UDP)
│ └─ 查找绑定了该地址端口的 ADDRESS_FILE
│
└─ DGDeliverData(AddrFile, Src, Dst, SrcPort, DstPort, IPPacket, DataSize)
│
├─ 有接收请求 (ReceiveQueue) → 复制数据到用户缓冲
├─ 无请求但有事件处理器 → 调用 TDI_EVENT_RECEIVE_DATAGRAM
└─ 都没有 → 丢弃
3. UDP 报文格式
定义在 udp.h(file:///d:/reactos/drivers/network/tcpip/include/udp.h#L15-L20):
c
typedef struct UDP_HEADER {
USHORT SourcePort; // 源端口 (2 字节)
USHORT DestPort; // 目的端口 (2 字节)
USHORT Length; // UDP 头 + 数据长度 (2 字节)
USHORT Checksum; // 校验和 (2 字节, 可选)
} UDP_HEADER, *PUDP_HEADER;
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data (可变长度) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
最小 UDP 头: 8 字节(无数据时 Length = 8)
4. UDP 校验和
4.1 伪头 (Pseudo Header)
定义在 udp.h(file:///d:/reactos/drivers/network/tcpip/include/udp.h#L23-L29):
c
typedef struct UDP_PSEUDO_HEADER {
ULONG SourceAddress; // 源 IP 地址 (32 位)
ULONG DestAddress; // 目的 IP 地址 (32 位)
UCHAR Zero; // 保留 (0)
UCHAR Protocol; // 协议号 (17 = UDP)
USHORT UDPLength; // UDP 报文长度 (头+数据)
} UDP_PSEUDO_HEADER, *PUDP_PSEUDO_HEADER;
4.2 计算过程
UDPv4ChecksumCalculate(IPv4Header, UDPHeader, Length)
│
├─ 伪头 + UDP 头 + 数据 按 16 位字累加
│ 源地址 | 目的地址 | 0 | 17 | UDP长度
│ + UDP头 (8字节) + 数据
├─ 进位回卷
└─ 取反 → 校验和
4.3 校验和规则
| 情况 | 处理 |
|---|---|
| 发送时 | 计算校验和并填入 |
| 接收时 | 校验和不匹配 → 丢弃 |
| 校验和为 0 | 表示发送方未计算 (IPv4 可选),接受 |
| 计算结果为 0 | 填入 0xFFFF (避免与"未计算"混淆) |
接收验证逻辑 (在 UDPReceive):
c
i = UDPv4ChecksumCalculate(IPv4Header, UDPHeader, WH2N(UDPHeader->Length));
if (i != DH2N(0x0000FFFF) && UDPHeader->Checksum != 0)
{
/* 校验和不匹配且校验和字段非零 → 坏包 */
return; // 丢弃
}
5. 端口管理
5.1 端口范围
c
#define UDP_STARTING_PORT 0x8000 // 起始端口 32768
#define UDP_DYNAMIC_PORTS 0x8000 // 动态端口数 32768 (32768-65535)
5.2 PORT_SET 结构
UDP 使用通用端口管理基础设施(ports.c):
c
PORT_SET UDPPorts; // UDP 端口集
// 初始化: 端口范围 [1, 32768+32768] = [1, 65535]
PortsStartup(&UDPPorts, 1, UDP_STARTING_PORT + UDP_DYNAMIC_PORTS);
5.3 端口操作
| 函数 | 功能 |
|---|---|
UDPAllocatePort(HintPort) |
分配端口:有提示端口 → 尝试指定;否则从动态范围分配 |
UDPFreePort(Port) |
释放端口 |
AllocatePort(Ports, Port) |
分配指定端口 |
AllocatePortFromRange(Ports, Start, End) |
从范围分配 |
5.4 端口分配逻辑
UDPAllocatePort(HintPort)
│
├─ HintPort 非 0 (指定端口):
│ ├─ AllocatePort(UDPPorts, HintPort) 成功 → 返回 HintPort
│ └─ 失败 → 返回 (UINT)-1 (失败)
│
└─ HintPort == 0 (自动分配):
└─ AllocatePortFromRange(UDPPorts, 32768, 65535)
6. UDP 子系统初始化
6.1 UDPStartup
在 udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L336-L358):
UDPStartup()
│
├─ 清空 UDPStats (统计)
├─ PortsStartup(&UDPPorts, 1, 65535) // 初始化端口集
├─ IPRegisterProtocol(IPPROTO_UDP, UDPReceive) // 注册接收函数
├─ UDPInitialized = TRUE
└─ 返回成功
6.2 UDPShutdown
在 udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L361-L380):
UDPShutdown()
├─ 未初始化 → 直接返回
├─ PortsShutdown(&UDPPorts) // 清理端口集
├─ IPRegisterProtocol(IPPROTO_UDP, NULL) // 注销接收
└─ UDPInitialized = FALSE
6.3 UDP_STATISTICS
c
typedef struct UDP_STATISTICS {
ULONG InputDatagrams; // 接收的数据报数
ULONG NumPorts; // 端口数
ULONG InputErrors; // 接收错误数
ULONG OutputDatagrams; // 发送的数据报数
ULONG NumAddresses; // 地址数
} UDP_STATISTICS, *PUDP_STATISTICS;
7. UDP 发送路径
7.1 UDPSendDatagram --- 发送入口
在 udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L150-L237),是 ADDRESS_FILE->Send 回调的实现:
UDPSendDatagram(AddrFile, ConnInfo, BufferData, DataSize, DataUsed)
│
├─ LockObject(AddrFile)
│
├─ 1. 解析远端地址:
│ RemoteAddressTa = ConnInfo->RemoteAddress (PTA_IP_ADDRESS)
│ case TDI_ADDRESS_TYPE_IP:
│ RemoteAddress = in_addr (IP)
│ RemotePort = sin_port
│ default → 返回 STATUS_UNSUCCESSFUL
│
├─ 2. 确定本地地址:
│ LocalAddress = AddrFile->Address
│
│ 未指定 (0.0.0.0):
│ ├─ RouteGetRouteToDestination(RemoteAddress)
│ │ └─ 失败 → STATUS_NETWORK_UNREACHABLE
│ └─ LocalAddress = NCE->Interface->Unicast (接口单播地址)
│
│ 已指定:
│ └─ NBLocateNeighbor(LocalAddress)
│ └─ 失败 → STATUS_INVALID_PARAMETER
│
├─ 3. BuildUDPPacket(AddrFile, &Packet, RemoteAddress, RemotePort,
│ LocalAddress, AddrFile->Port, BufferData, DataSize)
│
├─ UnlockObject(AddrFile)
│
├─ 4. IPSendDatagram(&Packet, NCE) // 交给 IP 层
│ └─ 失败 → 返回状态
│
├─ 5. *DataUsed = DataSize
│
└─ 6. UDPStats.OutputDatagrams++
└─ 返回 STATUS_SUCCESS
7.2 BuildUDPPacket --- 构造 UDP 报文
在 udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L78-L148):
BuildUDPPacket(AddrFile, Packet, RemoteAddress, RemotePort,
LocalAddress, LocalPort, DataBuffer, DataLen)
│
├─ IPInitializePacket(Packet, IP_ADDRESS_V4)
├─ Packet->TotalSize = IPv4头(20) + UDP头(8) + DataLen
│
├─ AllocatePacketWithBuffer(&Packet->NdisPacket, NULL, TotalSize)
│
├─ switch (RemoteAddress->Type):
│ ├─ IP_ADDRESS_V4:
│ │ └─ AddUDPHeaderIPv4(AddrFile, Remote, RemotePort,
│ │ Local, LocalPort, Packet,
│ │ DataBuffer, DataLen)
│ └─ IP_ADDRESS_V6: 暂不支持
│
└─ 返回状态
7.3 AddUDPHeaderIPv4 --- 添加 IPv4+UDP 头
在 udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L16-L75):
AddUDPHeaderIPv4(AddrFile, RemoteAddress, RemotePort,
LocalAddress, LocalPort, IPPacket, Data, DataLength)
│
├─ AddGenericHeaderIPv4(...) // 通用 IPv4 头构造
│ └─ 分配头空间, 填充 IPv4 头 (含 IP 校验和)
│ └─ 返回 UDPHeader 指针
│
├─ 填充 UDP 头:
│ SourcePort = LocalPort (已是网络字节序)
│ DestPort = RemotePort (已是网络字节序)
│ Checksum = 0
│ Length = WH2N(DataLength + 8) // 头+数据
│
├─ 复制数据: RtlCopyMemory(IPPacket->Data, Data, DataLength)
│
└─ 计算 UDP 校验和:
UDPHeader->Checksum = UDPv4ChecksumCalculate(
(PIPv4_HEADER)IPPacket->Header, // IPv4 头 (伪头源)
(PUCHAR)UDPHeader, // UDP 头
DataLength + sizeof(UDP_HEADER));// 长度
UDPHeader->Checksum = WH2N(...) // 网络字节序
7.4 AddGenericHeaderIPv4 --- 通用 IPv4 头构造
在 routines.c(file:///d:/reactos/drivers/network/tcpip/ip/network/routines.c):
AddGenericHeaderIPv4(AddrFile, RemoteAddress, RemotePort,
LocalAddress, LocalPort, IPPacket,
DataLength, Protocol, HeaderSize, HeaderPtr)
│
├─ 设置 IP 头指针和大小:
│ IPPacket->HeaderSize = sizeof(IPv4_HEADER)
│ IPPacket->Data = Header + HeaderSize
│
├─ 填充 IPv4 头:
│ VerIHL = 0x45 (IPv4 + 20字节头)
│ Tos = 0
│ TotalLength = WH2N(HeaderSize + DataLength)
│ Id = WH2N(TCP_IPIdentification++)
│ FlagsFragOfs = 0
│ Ttl = 128
│ Protocol = IPPROTO_UDP (17)
│ Checksum = 0
│ SrcAddr = LocalAddress
│ DstAddr = RemoteAddress
│
├─ 计算 IP 头校验和
│
└─ 返回 *HeaderPtr 指向协议头位置
8. UDP 接收路径
8.1 UDPReceive --- 接收入口
在 udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L240-L333),作为 IPRegisterProtocol(IPPROTO_UDP, UDPReceive) 注册的协议处理函数:
UDPReceive(Interface, IPPacket)
│
├─ 1. 判断 IP 版本:
│ ├─ IP_ADDRESS_V4: 解析 IPv4Header/DstAddress/SrcAddress
│ ├─ IP_ADDRESS_V6: 暂不支持 → 丢弃
│ └─ 其他 → 丢弃
│
├─ 2. 解析 UDP 头:
│ UDPHeader = (PUDP_HEADER)IPPacket->Data
│
├─ 3. 校验和验证:
│ i = UDPv4ChecksumCalculate(IPv4Header, UDPHeader, Length)
│ 结果 != 0xFFFF 且 Checksum != 0 → 丢弃 (坏包)
│
├─ 4. 长度验证:
│ Length < 8 (最小 UDP 头) → 丢弃
│ Length > IPPacket 数据区 → 丢弃
│
├─ 5. 计算数据大小:
│ DataSize = Length - sizeof(UDP_HEADER)
│
├─ 6. 定位数据区域:
│ IPPacket->Data += sizeof(UDP_HEADER) // 跳过 UDP 头
│
├─ 7. 查找地址文件:
│ AddrFile = AddrSearchFirst(DstAddress, DestPort, IPPROTO_UDP, &ctx)
│ └─ 遍历匹配 (目的 IP, 目的端口, UDP 协议) 的地址文件
│
├─ 8. 投递:
│ do {
│ DGDeliverData(AddrFile, Src, Dst, SrcPort, DstPort,
│ IPPacket, DataSize);
│ DereferenceObject(AddrFile);
│ } while ((AddrFile = AddrSearchNext(&ctx)) != NULL);
│ └─ 所有匹配的地址文件都收到副本 (广播/多播场景)
│
├─ 9. 无地址文件:
│ └─ 无法投递 → 丢弃 (FIXME: 应发 ICMP Port Unreachable)
│
└─ 10. UDPStats.InputDatagrams++
8.2 AddrSearchFirst/Next --- 地址文件查找
按 (目的地址, 目的端口, 协议号) 查找绑定的地址文件:
AddrSearchFirst(Address, Port, Protocol, SearchContext)
├─ 遍历 AddressFileListHead
├─ 匹配条件:
│ ├─ AddrFile->Protocol == Protocol (UDP)
│ ├─ AddrFile->Port == Port
│ └─ AddrFile->Address == Address 或 通配 (0.0.0.0)
└─ 返回第一个匹配 (或 NULL)
AddrSearchNext(SearchContext)
└─ 继续遍历返回下一个匹配
9. 数据报基础设施 (datagram.c)
实现在 datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c),为 UDP 和 Raw IP 提供通用的收发基础设施。
9.1 接收请求结构 (DATAGRAM_RECEIVE_REQUEST)
定义在 titypes.h(file:///d:/reactos/drivers/network/tcpip/include/titypes.h#L76-L89):
c
typedef struct _DATAGRAM_RECEIVE_REQUEST {
struct _ADDRESS_FILE *AddressFile; // 所属地址文件
LIST_ENTRY ListEntry; // 接收请求队列
IP_ADDRESS RemoteAddress; // 过滤: 远端地址 (0=任意)
USHORT RemotePort; // 过滤: 远端端口 (0=任意)
PTDI_CONNECTION_INFORMATION ReturnInfo; // 返回信息 (来源地址)
PCHAR Buffer; // 接收缓冲
ULONG BufferSize; // 缓冲大小
DATAGRAM_COMPLETION_ROUTINE Complete; // 完成回调
PVOID Context;
DATAGRAM_COMPLETION_ROUTINE UserComplete; // 用户完成回调
PVOID UserContext;
PIRP Irp; // 用户 IRP
} DATAGRAM_RECEIVE_REQUEST, *PDATAGRAM_RECEIVE_REQUEST;
9.2 DGReceiveDatagram --- 挂起接收请求
在 datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L226-L317):
DGReceiveDatagram(AddrFile, ConnInfo, BufferData, ReceiveLength,
ReceiveFlags, ReturnInfo, BytesReceived,
Complete, Context, Irp)
│
├─ LockObject(AddrFile)
│
├─ 分配 DATAGRAM_RECEIVE_REQUEST
│
├─ 提取远端过滤:
│ ├─ ConnInfo->RemoteAddress 非空:
│ │ └─ AddrGetAddress → RemoteAddress + RemotePort
│ └─ 空 → RemotePort = 0, RemoteAddress = 0.0.0.0 (任意)
│
├─ IoMarkIrpPending(Irp)
│
├─ 初始化请求:
│ ReturnInfo / Buffer / BufferSize
│ UserComplete = Complete / UserContext = Context
│ Complete = DGReceiveComplete
│ Irp = Irp
│
├─ InsertTailList(&AddrFile->ReceiveQueue, &Request->ListEntry)
│
├─ UnlockObject(AddrFile)
│
└─ 返回 STATUS_PENDING // 异步等待数据到达
9.3 DGReceiveComplete --- 接收完成回调
在 datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L217-L224):
DGReceiveComplete(Context, Status, Count)
├─ ReceiveRequest = Context
├─ ReceiveRequest->UserComplete(UserContext, Status, Count)
└─ ExFreePool(ReceiveRequest) // 释放请求结构
9.4 DGRemoveIRP --- 取消接收请求
在 datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L13-L49):
DGRemoveIRP(AddrFile, Irp)
├─ LockObject(AddrFile)
├─ 遍历 ReceiveQueue 查找 Irp 匹配的请求
│ └─ 找到 → 移除 + 释放 + 返回 TRUE
├─ UnlockObject
└─ 返回 FALSE (未找到)
10. 数据投递逻辑 (DGDeliverData)
在 datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L51-L215),是数据报到达后的核心投递函数:
10.1 投递优先级
DGDeliverData(AddrFile, SrcAddress, DstAddress, SrcPort, DstPort,
IPPacket, DataSize)
│
├─ LockObject(AddrFile)
│
├─ 1. 确定数据缓冲:
│ AddrFile->Protocol == IPPROTO_UDP:
│ DataBuffer = IPPacket->Data (跳过 UDP 头)
│ AddrFile->HeaderIncl:
│ DataBuffer = IPPacket->Header (含 IP 头, Raw IP)
│ 其他:
│ DataBuffer = IPPacket->Data
│ DataSize -= IPPacket->HeaderSize
│
├─ 2. 有挂起的接收请求 (ReceiveQueue 非空)?
│ │
│ ├─ 遍历请求队列查找匹配:
│ │ └─ 匹配条件:
│ │ DstPort == AddrFile->Port
│ │ AND (DstAddress 匹配 AddrFile->Address 或通配)
│ │
│ ├─ 找到匹配请求:
│ │ ├─ RemoveEntryList (从队列移除)
│ │ ├─ RtlCopyMemory(用户缓冲, 数据, MIN(BufferSize, DataSize))
│ │ ├─ 填充 ReturnInfo (来源 IP + 端口)
│ │ ├─ 完成:
│ │ │ BufferSize < DataSize → STATUS_BUFFER_OVERFLOW
│ │ │ 否则 → STATUS_SUCCESS + DataSize
│ │ └─ 释放请求
│ │
│ └─ 无匹配 → 数据保留 (等下一个请求)
│
├─ 3. 无挂起请求但注册了事件处理器?
│ │
│ └─ 调用 TDI_EVENT_RECEIVE_DATAGRAM 处理器:
│ (*ReceiveHandler)(HandlerContext,
│ AddressLength, SourceAddress, // 来源地址
│ OptionsSize, OptionsData, // IP 选项
│ TDI_RECEIVE_ENTIRE_MESSAGE,
│ DataSize, DataSize, // 指示/可用
│ &BytesTaken, DataBuffer, // 数据
│ NULL);
│
├─ 4. 都没有 → 丢弃数据报
│
└─ UnlockObject(AddrFile)
10.2 投递匹配规则
接收请求匹配:
DstPort == AddrFile->Port // 目的端口必须一致
AND (DstAddress == AddrFile->Address // 目的地址一致
OR AddrFile->Address 未指定 // 地址文件绑定 0.0.0.0
OR DstAddress 未指定) // 广播
11. 工作流程图
11.1 UDP 发送流程
#mermaid-svg-mPOiFXQyBW6NSvw7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mPOiFXQyBW6NSvw7 .error-icon{fill:#552222;}#mermaid-svg-mPOiFXQyBW6NSvw7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mPOiFXQyBW6NSvw7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .marker.cross{stroke:#333333;}#mermaid-svg-mPOiFXQyBW6NSvw7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mPOiFXQyBW6NSvw7 p{margin:0;}#mermaid-svg-mPOiFXQyBW6NSvw7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .cluster-label text{fill:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .cluster-label span{color:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .cluster-label span p{background-color:transparent;}#mermaid-svg-mPOiFXQyBW6NSvw7 .label text,#mermaid-svg-mPOiFXQyBW6NSvw7 span{fill:#333;color:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .node rect,#mermaid-svg-mPOiFXQyBW6NSvw7 .node circle,#mermaid-svg-mPOiFXQyBW6NSvw7 .node ellipse,#mermaid-svg-mPOiFXQyBW6NSvw7 .node polygon,#mermaid-svg-mPOiFXQyBW6NSvw7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .rough-node .label text,#mermaid-svg-mPOiFXQyBW6NSvw7 .node .label text,#mermaid-svg-mPOiFXQyBW6NSvw7 .image-shape .label,#mermaid-svg-mPOiFXQyBW6NSvw7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-mPOiFXQyBW6NSvw7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .rough-node .label,#mermaid-svg-mPOiFXQyBW6NSvw7 .node .label,#mermaid-svg-mPOiFXQyBW6NSvw7 .image-shape .label,#mermaid-svg-mPOiFXQyBW6NSvw7 .icon-shape .label{text-align:center;}#mermaid-svg-mPOiFXQyBW6NSvw7 .node.clickable{cursor:pointer;}#mermaid-svg-mPOiFXQyBW6NSvw7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .arrowheadPath{fill:#333333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mPOiFXQyBW6NSvw7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mPOiFXQyBW6NSvw7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mPOiFXQyBW6NSvw7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mPOiFXQyBW6NSvw7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .cluster text{fill:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 .cluster span{color:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mPOiFXQyBW6NSvw7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mPOiFXQyBW6NSvw7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-mPOiFXQyBW6NSvw7 .icon-shape,#mermaid-svg-mPOiFXQyBW6NSvw7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mPOiFXQyBW6NSvw7 .icon-shape p,#mermaid-svg-mPOiFXQyBW6NSvw7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mPOiFXQyBW6NSvw7 .icon-shape .label rect,#mermaid-svg-mPOiFXQyBW6NSvw7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mPOiFXQyBW6NSvw7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mPOiFXQyBW6NSvw7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mPOiFXQyBW6NSvw7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} TDI_ADDRESS_TYPE_IP
其他
是
否
是
否
上层 TDI_SEND_DATAGRAM
DispTdiSendDatagram
AddrFile->Send = UDPSendDatagram
LockObject AddrFile
解析远端地址 TA_IP_ADDRESS
地址类型
获取 RemoteAddress + RemotePort
返回错误
本地地址未指定?
RouteGetRouteToDestination
找到路由?
STATUS_NETWORK_UNREACHABLE
LocalAddress = 接口单播地址
NBLocateNeighbor 本地地址
BuildUDPPacket
IPInitializePacket
AllocatePacketWithBuffer
AddUDPHeaderIPv4
AddGenericHeaderIPv4 填充 IPv4 头
填充 UDP 头 SourcePort/DestPort/Length
复制数据
计算 UDP 校验和
UnlockObject
IPSendDatagram 交给 IP 层
路由/分片/邻居/接口层
DataUsed = DataSize 返回成功
11.2 UDP 接收流程
#mermaid-svg-o2VSsMiCkWKS3SDF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o2VSsMiCkWKS3SDF .error-icon{fill:#552222;}#mermaid-svg-o2VSsMiCkWKS3SDF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o2VSsMiCkWKS3SDF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o2VSsMiCkWKS3SDF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o2VSsMiCkWKS3SDF .marker.cross{stroke:#333333;}#mermaid-svg-o2VSsMiCkWKS3SDF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o2VSsMiCkWKS3SDF p{margin:0;}#mermaid-svg-o2VSsMiCkWKS3SDF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF .cluster-label text{fill:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF .cluster-label span{color:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF .cluster-label span p{background-color:transparent;}#mermaid-svg-o2VSsMiCkWKS3SDF .label text,#mermaid-svg-o2VSsMiCkWKS3SDF span{fill:#333;color:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF .node rect,#mermaid-svg-o2VSsMiCkWKS3SDF .node circle,#mermaid-svg-o2VSsMiCkWKS3SDF .node ellipse,#mermaid-svg-o2VSsMiCkWKS3SDF .node polygon,#mermaid-svg-o2VSsMiCkWKS3SDF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o2VSsMiCkWKS3SDF .rough-node .label text,#mermaid-svg-o2VSsMiCkWKS3SDF .node .label text,#mermaid-svg-o2VSsMiCkWKS3SDF .image-shape .label,#mermaid-svg-o2VSsMiCkWKS3SDF .icon-shape .label{text-anchor:middle;}#mermaid-svg-o2VSsMiCkWKS3SDF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o2VSsMiCkWKS3SDF .rough-node .label,#mermaid-svg-o2VSsMiCkWKS3SDF .node .label,#mermaid-svg-o2VSsMiCkWKS3SDF .image-shape .label,#mermaid-svg-o2VSsMiCkWKS3SDF .icon-shape .label{text-align:center;}#mermaid-svg-o2VSsMiCkWKS3SDF .node.clickable{cursor:pointer;}#mermaid-svg-o2VSsMiCkWKS3SDF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o2VSsMiCkWKS3SDF .arrowheadPath{fill:#333333;}#mermaid-svg-o2VSsMiCkWKS3SDF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o2VSsMiCkWKS3SDF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o2VSsMiCkWKS3SDF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o2VSsMiCkWKS3SDF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o2VSsMiCkWKS3SDF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o2VSsMiCkWKS3SDF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o2VSsMiCkWKS3SDF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o2VSsMiCkWKS3SDF .cluster text{fill:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF .cluster span{color:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o2VSsMiCkWKS3SDF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o2VSsMiCkWKS3SDF rect.text{fill:none;stroke-width:0;}#mermaid-svg-o2VSsMiCkWKS3SDF .icon-shape,#mermaid-svg-o2VSsMiCkWKS3SDF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o2VSsMiCkWKS3SDF .icon-shape p,#mermaid-svg-o2VSsMiCkWKS3SDF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o2VSsMiCkWKS3SDF .icon-shape .label rect,#mermaid-svg-o2VSsMiCkWKS3SDF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o2VSsMiCkWKS3SDF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o2VSsMiCkWKS3SDF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o2VSsMiCkWKS3SDF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 17 UDP
V4
V6
否
是
否
是
否
是
是
是
否
否
是
否
IP 层 IPDispatchProtocol
协议号
UDPReceive
IP 版本
解析 IPv4/UDP 头
丢弃暂不支持
校验 UDP 校验和
校验和有效?
丢弃
长度验证
长度合法?
丢弃
DataSize = Length - 8
跳过 UDP 头定位数据
AddrSearchFirst 查找地址文件
找到?
丢弃 FIXME: ICMP
DGDeliverData
有接收请求?
匹配请求队列
找到匹配?
复制数据到用户缓冲
填充 ReturnInfo 来源地址
完成请求 IRP
数据保留
有事件处理器?
调用 TDI_EVENT_RECEIVE_DATAGRAM
丢弃
11.3 端口分配流程
#mermaid-svg-KItjKZrHvKMWQCZe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KItjKZrHvKMWQCZe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KItjKZrHvKMWQCZe .error-icon{fill:#552222;}#mermaid-svg-KItjKZrHvKMWQCZe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KItjKZrHvKMWQCZe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KItjKZrHvKMWQCZe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KItjKZrHvKMWQCZe .marker.cross{stroke:#333333;}#mermaid-svg-KItjKZrHvKMWQCZe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KItjKZrHvKMWQCZe p{margin:0;}#mermaid-svg-KItjKZrHvKMWQCZe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KItjKZrHvKMWQCZe .cluster-label text{fill:#333;}#mermaid-svg-KItjKZrHvKMWQCZe .cluster-label span{color:#333;}#mermaid-svg-KItjKZrHvKMWQCZe .cluster-label span p{background-color:transparent;}#mermaid-svg-KItjKZrHvKMWQCZe .label text,#mermaid-svg-KItjKZrHvKMWQCZe span{fill:#333;color:#333;}#mermaid-svg-KItjKZrHvKMWQCZe .node rect,#mermaid-svg-KItjKZrHvKMWQCZe .node circle,#mermaid-svg-KItjKZrHvKMWQCZe .node ellipse,#mermaid-svg-KItjKZrHvKMWQCZe .node polygon,#mermaid-svg-KItjKZrHvKMWQCZe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KItjKZrHvKMWQCZe .rough-node .label text,#mermaid-svg-KItjKZrHvKMWQCZe .node .label text,#mermaid-svg-KItjKZrHvKMWQCZe .image-shape .label,#mermaid-svg-KItjKZrHvKMWQCZe .icon-shape .label{text-anchor:middle;}#mermaid-svg-KItjKZrHvKMWQCZe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KItjKZrHvKMWQCZe .rough-node .label,#mermaid-svg-KItjKZrHvKMWQCZe .node .label,#mermaid-svg-KItjKZrHvKMWQCZe .image-shape .label,#mermaid-svg-KItjKZrHvKMWQCZe .icon-shape .label{text-align:center;}#mermaid-svg-KItjKZrHvKMWQCZe .node.clickable{cursor:pointer;}#mermaid-svg-KItjKZrHvKMWQCZe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KItjKZrHvKMWQCZe .arrowheadPath{fill:#333333;}#mermaid-svg-KItjKZrHvKMWQCZe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KItjKZrHvKMWQCZe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KItjKZrHvKMWQCZe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KItjKZrHvKMWQCZe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KItjKZrHvKMWQCZe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KItjKZrHvKMWQCZe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KItjKZrHvKMWQCZe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KItjKZrHvKMWQCZe .cluster text{fill:#333;}#mermaid-svg-KItjKZrHvKMWQCZe .cluster span{color:#333;}#mermaid-svg-KItjKZrHvKMWQCZe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KItjKZrHvKMWQCZe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KItjKZrHvKMWQCZe rect.text{fill:none;stroke-width:0;}#mermaid-svg-KItjKZrHvKMWQCZe .icon-shape,#mermaid-svg-KItjKZrHvKMWQCZe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KItjKZrHvKMWQCZe .icon-shape p,#mermaid-svg-KItjKZrHvKMWQCZe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KItjKZrHvKMWQCZe .icon-shape .label rect,#mermaid-svg-KItjKZrHvKMWQCZe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KItjKZrHvKMWQCZe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KItjKZrHvKMWQCZe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KItjKZrHvKMWQCZe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
是
否
否
UDPAllocatePort HintPort
HintPort 指定?
AllocatePort 指定端口
成功?
返回 HintPort
返回失败
AllocatePortFromRange 32768-65535
返回动态端口
12. 数据流图
12.1 完整的 UDP 发送数据流
应用程序 sendto()
│
▼
AFD → msafd → NtDeviceIoControlFile(IOCTL_AFD_SEND_DATAGRAM)
│
▼
AFD.sys → AfdPacketSocketWriteData → TdiSendDatagram
│
▼
tcpip.sys: DispTdiSendDatagram → AddrFile->Send
│
▼
UDPSendDatagram
│
│ UDP 报文构造:
│ ┌───────────────────────────────────────┐
│ │ IPv4 头 (20B) │
│ │ VerIHL=0x45, TTL=128, Proto=17 │
│ │ Src=接口IP, Dst=远端IP │
│ ├───────────────────────────────────────┤
│ │ UDP 头 (8B) │
│ │ SourcePort = 本地端口 │
│ │ DestPort = 远端端口 │
│ │ Length = 8 + 数据长度 │
│ │ Checksum = UDP伪头校验和 │
│ ├───────────────────────────────────────┤
│ │ 数据 (应用负载) │
│ └───────────────────────────────────────┘
│
▼
IPSendDatagram → 路由 → 分片 → NBQueuePacket
│
▼
网络接口层 → LANTransmit → NdisSend → 网卡
12.2 完整的 UDP 接收数据流
网卡 → NDIS → 网络接口层 → IPReceive → IPv4Receive
│
▼
ProcessFragment → 重组完成 → IPDispatchProtocol
│
▼
UDPReceive
│
│ 数据报:
│ ┌───────────────────────────────────────┐
│ │ IPv4 头 (20B) │
│ ├───────────────────────────────────────┤
│ │ UDP 头 (8B) │
│ │ SourcePort = 发送方端口 │
│ │ DestPort = 本地端口 │
│ │ Length / Checksum │
│ ├───────────────────────────────────────┤
│ │ 数据 │
│ └───────────────────────────────────────┘
│ ▲ IPPacket->Data 跳过 UDP 头
│
▼
AddrSearchFirst(目的IP, 目的端口, UDP)
│
▼
DGDeliverData
│
├─ 方式A: 有挂起接收请求
│ └─ 复制数据到用户缓冲 → 完成 IRP → 上层 recvfrom() 返回
│
└─ 方式B: 事件处理器
└─ TDI_EVENT_RECEIVE_DATAGRAM → 上层回调
12.3 地址文件投递匹配
UDP 数据报: Dst=192.168.1.100:53
│
▼
AddrSearchFirst(192.168.1.100, 53, IPPROTO_UDP)
│
├─ 遍历 AddressFileListHead:
│ ├─ AddrFile1: Port=53, Address=192.168.1.100 → 匹配 ✓
│ ├─ AddrFile2: Port=53, Address=0.0.0.0 → 匹配 ✓ (通配)
│ ├─ AddrFile3: Port=80, Address=192.168.1.100 → 不匹配 (端口)
│ └─ AddrFile4: Port=53, Address=10.0.0.5 → 不匹配 (地址)
│
└─ 匹配的文件都通过 DGDeliverData 投递
13. 关键函数索引
13.1 UDP 核心 (udp.c)
| 函数 | 位置 | 说明 |
|---|---|---|
UDPStartup |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L336-L358) | 初始化 UDP 子系统 |
UDPShutdown |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L361-L380) | 清理 UDP 子系统 |
UDPSendDatagram |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L150-L237) | UDP 发送入口 |
UDPReceive |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L240-L333) | UDP 接收入口 |
BuildUDPPacket |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L78-L148) | 构造 UDP 报文 |
AddUDPHeaderIPv4 |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L16-L75) | 添加 IPv4+UDP 头 |
UDPAllocatePort |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L382-L389) | 分配端口 |
UDPFreePort |
udp.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/udp/udp.c#L391-L393) | 释放端口 |
13.2 数据报基础设施 (datagram.c)
| 函数 | 位置 | 说明 |
|---|---|---|
DGReceiveDatagram |
datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L226-L317) | 挂起接收请求 |
DGDeliverData |
datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L51-L215) | 数据投递核心 |
DGReceiveComplete |
datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L217-L224) | 接收完成回调 |
DGRemoveIRP |
datagram.c(file:///d:/reactos/drivers/network/tcpip/ip/transport/datagram/datagram.c#L13-L49) | 取消接收请求 |
13.3 相关辅助
| 函数 | 位置 | 说明 |
|---|---|---|
AddGenericHeaderIPv4 |
routines.c(file:///d:/reactos/drivers/network/tcpip/ip/network/routines.c) | 通用 IPv4 头构造 |
AddrSearchFirst / AddrSearchNext |
address.c(file:///d:/reactos/drivers/network/tcpip/ip/network/address.c) | 地址文件查找 |
AddrGetAddress |
address.c(file:///d:/reactos/drivers/network/tcpip/ip/network/address.c) | 地址解析 |
PortsStartup / AllocatePort |
ports.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ports.c) | 端口管理 |
UDPv4ChecksumCalculate |
checksum.c(file:///d:/reactos/drivers/network/tcpip/ip/network/checksum.c) | UDP 校验和 |
IPRegisterProtocol |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c) | 协议注册 |
IPSendDatagram |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L223) | IP 发送 |
附录 A:UDP 头文件
| 头文件 | 路径 | 内容 |
|---|---|---|
udp.h |
include/udp.h(file:///d:/reactos/drivers/network/tcpip/include/udp.h) | UDP_HEADER、伪头、统计、函数声明 |
datagram.h |
include/datagram.h(file:///d:/reactos/drivers/network/tcpip/include/datagram.h) | 数据报结构声明 |
titypes.h |
include/titypes.h(file:///d:/reactos/drivers/network/tcpip/include/titypes.h) | DATAGRAM_RECEIVE_REQUEST 等 |
address.h |
include/address.h(file:///d:/reactos/drivers/network/tcpip/include/address.h) | 地址管理 |
附录 B:参考文档
- tcpip网络层IP分析(file:///d:/reactos/doc/tcpip网络层IP分析.md) --- IP 网络层 (下层)
- TCPIP 驱动分析(file:///d:/reactos/doc/TCPIP_驱动分析.md) --- tcpip.sys 整体
- TDI传输驱动接口分析(file:///d:/reactos/doc/TDI传输驱动接口分析.md) --- TDI 接口 (上层)
- RFC 768 --- User Datagram Protocol