tcpip.sys 传输层 (UDP) 详细分析

tcpip.sys 传输层 (UDP) 详细分析

目录

  1. 概述
  2. [UDP 层整体架构](#UDP 层整体架构)
  3. [UDP 报文格式](#UDP 报文格式)
  4. [UDP 校验和](#UDP 校验和)
  5. 端口管理
  6. [UDP 子系统初始化](#UDP 子系统初始化)
  7. [UDP 发送路径](#UDP 发送路径)
  8. [UDP 接收路径](#UDP 接收路径)
  9. 数据报基础设施 (datagram.c)
  10. 数据投递逻辑 (DGDeliverData)
  11. 工作流程图
  12. 数据流图
  13. 关键函数索引

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
相关推荐
SendTomo1 小时前
send.wang私传网:P2P直连传大文件首选工具
javascript·网络·网络协议·webrtc·p2p
llllll1521 小时前
HTTP协议全解:从报文结构到HTTPS加密原理
网络协议·http·https
珠***格12 小时前
双碳目标下:四可装置如何助力光伏消纳与碳数据上报
网络·人工智能·分布式·安全·边缘计算
mounter62513 小时前
绕过主机:通过 Devmem TCP 运行 RDMA 应用
网络·网络协议·tcp/ip·rdma·devmem
我星期八休息14 小时前
网络编程—网络层
开发语言·前端·网络·人工智能·智能路由器
科力锐品牌君15 小时前
行业龙头|科力锐全链路防勒索 + 多中心容灾方案,构筑河南翔宇医疗业务安全闭环!
网络·数据库·分布式·安全·数据安全·备份
2401_8685347816 小时前
C语言与C++在基础语法上的区别
网络·网络协议
黄俊懿16 小时前
【架构师从入门到进阶】第五章:DNS&CDN&网关优化思路——第三节:CDN扩展-多地址直连
网络·计算机网络·架构·系统架构·cdn·dns·架构设计
Dr.kangder17 小时前
嵌入式总线设备解析——TTE总线应用与实践
开发语言·网络·算法·嵌入式·多任务·同步机制