tcpip.sys 网络层 (IP) 详细分析
目录
- 概述
- [IP 层整体架构](#IP 层整体架构)
- [IPv4 报文格式](#IPv4 报文格式)
- [IP 数据包结构 (IP_PACKET)](#IP 数据包结构 (IP_PACKET))
- 协议表与分发机制
- [IP 接收路径](#IP 接收路径)
- [IP 分片重组 (RFC 815)](#IP 分片重组 (RFC 815))
- [IP 发送路径](#IP 发送路径)
- [IP 分片发送](#IP 分片发送)
- 路由系统
- [ICMP 协议](#ICMP 协议)
- 校验和计算
- 工作流程图
- 数据流图
- 关键函数索引
1. 概述
IP 网络层 是 TCP/IP 协议栈的第三层(对应 OSI 网络层),负责数据报的寻址、路由和转发。在 ReactOS tcpip.sys 中,IP 层位于传输层(TCP/UDP)与网络接口层(LAN/邻居/ARP)之间。
┌─────────────────────────────────────────────┐
│ 传输层 (TCP/UDP/ICMP/RawIP) │
└──────────────────┬──────────────────────────┘
│ 协议号分发 (ProtocolTable)
┌──────────────────▼──────────────────────────┐
│ IP 网络层 ←★ │
│ │
│ 接收: IPReceive → IPv4Receive │
│ → 校验和验证 → 分片重组 (RFC 815) │
│ → 协议分发 │
│ │
│ 发送: IPTransmitPacket → 路由查找 │
│ → 分片 → NBQueuePacket → 接口层 │
│ │
│ 路由: Router* (FIB) / 转发决策 │
│ 控制: ICMP 差错报告 / 回显 │
│ 地址: IPv4 地址管理 │
└──────────────────┬──────────────────────────┘
│ 网络接口层 (LAN/邻居/ARP)
▼
NDIS → 物理网卡
1.1 核心职责
- 数据报接收:验证 IP 头、校验和、分片重组、按协议号分发
- 数据报发送:路由选择、MTU 分片、交付网络接口层
- 路由转发:目的地址不在本机时转发到下一跳
- ICMP 支持:差错报告(目的不可达等)和回显(ping)
- 地址管理:接口 IP 地址的增删改查
1.2 IP 层源码模块
| 源文件 | 职责 |
|---|---|
ip.c |
IP 模块初始化、协议表、接口注册 |
receive.c |
数据报接收、分片重组 (RFC 815) |
transmit.c |
数据报发送、分片 |
router.c |
路由表 (FIB) 管理 |
address.c |
IP 地址管理 (IPv4/IPv6) |
icmp.c |
ICMP 协议 |
checksum.c |
IP/TCP/UDP 校验和 (含 x86 汇编) |
ports.c |
端口分配 |
routines.c |
辅助工具 |
2. IP 层整体架构
2.1 接收路径架构
网络接口层 (LanReceiveWorker)
│ 按以太网类型分发
▼
IPReceive(IF, IPPacket) ← ip.c / receive.c
│
▼
IPv4Receive(IF, IPPacket) ← receive.c
├─ 解析 IP 头 (HeaderSize/TotalSize/SrcAddr/DstAddr)
├─ IPv4CorrectChecksum 验证
└─ ProcessFragment(IF, IPPacket) ← 分片处理
│
├─ 完整数据报 → 直接分发
├─ 分片 → GetReassemblyInfo 查找/创建 IPDR
│ └─ 空洞描述符算法 (RFC 815)
│ └─ 重组完成 → ReassembleDatagram
└─ IPDispatchProtocol(IF, &Datagram) ← 协议分发
│
├─ ProtocolTable[6] → TCPReceive
├─ ProtocolTable[17] → UDPReceive
├─ ProtocolTable[1] → ICMPReceive
└─ ProtocolTable[0] → RawIPReceive
2.2 发送路径架构
传输层调用 (TCP 发送 / UDP 发送 / ICMP 发送)
│
├─ TCPTransmitPacket
├─ UDPTransmitPacket
└─ ICMPTransmitPacket
│
▼
IPTransmitPacket(Packet, NCE, IF, Address) ← transmit.c
│
├─ 填充 IPv4 头 (版本/长度/ID/标志/TTL/协议/校验和)
│
└─ IPSendDatagram(IPPacket, NCE)
│
└─ SendFragments(IPPacket, NCE, PathMTU)
│
├─ 包 ≤ MTU → 单片段直接发送
└─ 包 > MTU → 循环 PrepareNextFragment 分片
│
└─ IPSendFragment(NdisPacket, NCE, IFC)
│
└─ NBQueuePacket(NCE, ...) ← 邻居缓存排队
│
└─ 网络接口层 (LANTransmit)
2.3 路由系统架构
路由表 (FIB - Forwarding Information Base)
│
├─ RouterCreateRoute(Target, Mask, Router, Interface) ← 添加
├─ RouterRemoveRoute(Target, Router) ← 删除
├─ RouterRemoveRoutesForInterface(IF) ← 按接口删除
│
└─ 查找: RouteGetRouteToDestination(Address)
├─ 精确匹配 → 直连路由 → NCE (邻居)
├─ 最长前缀匹配 → 下一跳路由
└─ 默认路由 (0.0.0.0/0)
3. IPv4 报文格式
定义在 ip.h(file:///d:/reactos/drivers/network/tcpip/include/ip.h#L37-L48):
c
typedef struct IPv4_HEADER {
UCHAR VerIHL; // 版本(4位) + 头长度(4位, 单位32位字)
UCHAR Tos; // 服务类型
USHORT TotalLength; // 总长度 (头+数据)
USHORT Id; // 标识 (分片用)
USHORT FlagsFragOfs; // 标志(3位) + 片偏移(13位)
UCHAR Ttl; // 生存时间
UCHAR Protocol; // 上层协议号
USHORT Checksum; // 头校验和
IPv4_RAW_ADDRESS SrcAddr; // 源 IP 地址
IPv4_RAW_ADDRESS DstAddr; // 目的 IP 地址
} IPv4_HEADER, *PIPv4_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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
标志位常量:
c
#define IPv4_FRAGOFS_MASK 0x1FFF // 片偏移掩码
#define IPv4_MF_MASK 0x2000 // 更多分片标志
#define IPv4_DF_MASK 0x4000 // 不分片标志
#define IPv4_MAX_HEADER_SIZE 60 // 最大头大小 (含选项)
协议号:
c
#define IPPROTO_RAW 0 // Raw IP
#define IPPROTO_ICMP 1 // Internet Control Message Protocol
#define IPPROTO_IGMP 2 // Internet Group Management Protocol
#define IPPROTO_TCP 6 // Transmission Control Protocol
#define IPPROTO_UDP 17 // User Datagram Protocol
IPv6 头:
c
typedef struct IPv6_HEADER {
ULONG VTF; // 版本 + 流量类型 + 流标签
USHORT PayloadLength; // 载荷长度
UCHAR NextHeader; // 下一个头 (同 IPv4 Protocol)
UCHAR HopLimit; // 跳数限制 (同 IPv4 TTL)
IPv6_RAW_ADDRESS SrcAddr; // 128 位源地址
IPv6_RAW_ADDRESS DstAddr; // 128 位目的地址
} IPv6_HEADER, *PIPv6_HEADER;
4. IP 数据包结构 (IP_PACKET)
定义在 ip.h(file:///d:/reactos/drivers/network/tcpip/include/ip.h#L77-L91):
c
typedef struct _IP_PACKET {
OBJECT_FREE_ROUTINE Free; // 释放函数 (DeinitializePacket)
UCHAR Type; // IP_ADDRESS_V4 (0x04) / IP_ADDRESS_V6 (0x06)
UCHAR Flags; // IP_PACKET_FLAG_RAW (0x01)
BOOLEAN MappedHeader; // Header 是否直接映射 NDIS 包 (TRUE=无需释放)
BOOLEAN ReturnPacket; // NdisPacket 是否需要 NdisReturnPackets
PVOID Header; // IP 头指针
UINT HeaderSize; // IP 头大小
PVOID Data; // 数据指针 (头之后)
UINT TotalSize; // 总大小 (头+数据)
UINT Position; // 当前逻辑偏移 (帧内位置)
PNDIS_PACKET NdisPacket; // 底层 NDIS 包
IP_ADDRESS SrcAddr; // 源地址
IP_ADDRESS DstAddr; // 目的地址
} IP_PACKET, *PIP_PACKET;
IP_ADDRESS 地址结构:
c
typedef struct IP_ADDRESS {
UCHAR Type; // IP_ADDRESS_V4 / IP_ADDRESS_V6
union {
IPv4_RAW_ADDRESS IPv4Address; // 32 位 IPv4 (网络字节序)
IPv6_RAW_ADDRESS IPv6Address; // 128 位 IPv6
} Address;
} IP_ADDRESS, *PIP_ADDRESS;
#define IP_ADDRESS_V4 0x04
#define IP_ADDRESS_V6 0x06
包释放逻辑 (DeinitializePacket):
DeinitializePacket(IPPacket)
├─ 检查双重释放 (Type != 0xFF)
├─ NdisPacket 非空:
│ ├─ ReturnPacket → NdisReturnPackets (归还微型端口)
│ └─ 否则 → FreeNdisPacket (正常释放)
├─ !MappedHeader && Header → ExFreePool (释放池分配的头)
└─ 完成
包上下文 (PACKET_CONTEXT):
c
typedef struct _PACKET_CONTEXT {
PACKET_COMPLETION_ROUTINE DLComplete; // 链路层完成回调
PVOID Context; // 回调上下文
UINT PacketType; // 包类型
} PACKET_CONTEXT, *PPACKET_CONTEXT;
#define PC(Packet) ((PPACKET_CONTEXT)(&Packet->ProtocolReserved))
5. 协议表与分发机制
5.1 协议表
定义在 ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L25):
c
#define IP_PROTOCOL_TABLE_SIZE 0x100 // 256 项
typedef VOID (*IP_PROTOCOL_HANDLER)(
PIP_INTERFACE Interface, // 接收接口
PIP_PACKET IPPacket); // IP 数据包
IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
5.2 IPRegisterProtocol --- 协议注册
在 ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L386-L404):
IPRegisterProtocol(ProtocolNumber, Handler)
├─ ProtocolTable[ProtocolNumber] = Handler ? Handler : DefaultProtocolHandler
└─ 完成
各子系统启动时注册:
RawIPStartup → IPRegisterProtocol(IPPROTO_RAW, RawIPReceive)
UDPStartup → IPRegisterProtocol(IPPROTO_UDP, UDPReceive)
TCPStartup → IPRegisterProtocol(IPPROTO_TCP, TCPReceive)
ICMPStartup → IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive)
5.3 IPDispatchProtocol --- 协议分发
在 ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L142-L177):
IPDispatchProtocol(Interface, IPPacket)
│
├─ Protocol = IPHeader->Protocol (取协议号)
├─ 检查 Protocol < 256
│
└─ (*ProtocolTable[Protocol])(Interface, IPPacket)
└─ 未注册的协议 → DefaultProtocolHandler (丢弃 + 发送 ICMP 协议不可达)
5.4 DefaultProtocolHandler
未注册协议的默认处理(可能发送 ICMP Protocol Unreachable 并丢弃)。
6. IP 接收路径
6.1 IPReceive --- 入口
在 receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L638):
IPReceive(PIP_INTERFACE IF, PIP_PACKET IPPacket)
│
├─ IPPacket->Type 判断:
│ ├─ IP_ADDRESS_V4 → IPv4Receive(IF, IPPacket)
│ └─ IP_ADDRESS_V6 → 暂不支持/丢弃
│
└─ IPPacket->Free(IPPacket) // 释放 (在 IPv4Receive 中已分离)
6.2 IPv4Receive --- IPv4 数据报接收
在 receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L555-L635):
IPv4Receive(IF, IPPacket)
│
├─ 1. 读取第一个字节 → 解析头长度:
│ HeaderSize = (FirstByte & 0x0F) << 2 // 单位是 32 位字
│ HeaderSize > 60 → 丢弃
│
├─ 2. 分配 IP 头缓冲, 从 NDIS 包复制:
│ CopyPacketToBuffer(Header, NdisPacket, Position, HeaderSize)
│ IPPacket->MappedHeader = FALSE
│
├─ 3. 校验和验证:
│ IPv4CorrectChecksum(Header, HeaderSize) == FALSE → 丢弃
│
├─ 4. 解析:
│ TotalSize = WN2H(TotalLength) // 总长度
│ SrcAddr = Header->SrcAddr
│ DstAddr = Header->DstAddr
│
├─ 5. 更新接口统计 (InBytes/InUnicast/...)
│
└─ 6. ProcessFragment(IF, IPPacket) // 分片处理
6.3 统计更新
SEND_RECV_STATS:
InBytes // 接收字节数
InUnicast // 单播数
InNUnicast // 非单播数
InDiscarded // 丢弃数
InErrors // 错误数
InDiscardedUnknownProto // 未知协议丢弃
7. IP 分片重组 (RFC 815)
实现在 receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L271-L482),采用 RFC 815 的空洞描述符算法。
7.1 数据结构
c
/* 空洞描述符: 描述尚未收到的数据区间 */
typedef struct _IPDATAGRAM_HOLE {
LIST_ENTRY ListEntry;
ULONG First; // 区间首字节偏移
ULONG Last; // 区间末字节偏移
} IPDATAGRAM_HOLE, *PIPDATAGRAM_HOLE;
/* 分片描述符 */
typedef struct _IP_FRAGMENT {
LIST_ENTRY ListEntry;
UINT Size; // 分片数据大小
UINT Offset; // 在数据报中的偏移
UINT PacketOffset; // 在 NDIS 包中的偏移
PNDIS_PACKET Packet; // NDIS 包
BOOLEAN ReturnPacket; // 是否需要归还
} IP_FRAGMENT, *PIP_FRAGMENT;
/* 重组描述符: 一个完整数据报的组装状态 */
typedef struct _IPDATAGRAM_REASSEMBLY {
LIST_ENTRY ListEntry; // 全局 ReassemblyListHead
KSPIN_LOCK Lock;
UINT TimeoutCount; // 超时计数
ULONG Id; // 标识
UCHAR Protocol; // 协议号
IP_ADDRESS SrcAddr; // 源地址
IP_ADDRESS DstAddr; // 目的地址
LIST_ENTRY HoleListHead; // 空洞列表
LIST_ENTRY FragmentListHead; // 分片列表
PCHAR IPv4Header; // 第一个分片的 IP 头
UINT HeaderSize; // 头大小
UINT DataSize; // 数据总大小
} IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY;
7.2 识别与查找 (GetReassemblyInfo)
数据报由四元组唯一标识:
GetReassemblyInfo(IPPacket)
匹配条件:
├─ SrcAddr 相同
├─ DstAddr 相同
├─ Id 相同
└─ Protocol 相同
7.3 ProcessFragment --- 分片处理算法
ProcessFragment(IF, IPPacket)
│
├─ 1. 获取/创建 IPDR:
│ ├─ GetReassemblyInfo 找到 → 复用, 重置 TimeoutCount
│ └─ 新建:
│ ├─ 创建初始空洞 [0, 65536] (表示整个数据报未到)
│ ├─ 记录 SrcAddr/DstAddr/Id/Protocol
│ └─ 加入 ReassemblyListHead
│
├─ 2. 计算本分片区间:
│ FragFirst = (FlagsFragOfs & 0x1FFF) << 3 // 片偏移 × 8
│ FragLast = FragFirst + TotalLength
│ MoreFragments = FlagsFragOfs & 0x2000
│
├─ 3. 空洞匹配 (RFC 815):
│ 遍历 HoleList 寻找覆盖 [FragFirst, FragLast] 的空洞:
│
│ ┌────────────────────────────────────────┐
│ │ 空洞: [Hole->First ... Hole->Last] │
│ │ 分片: [FragFirst ... FragLast] │
│ │ │
│ │ 分片覆盖空洞的中间部分: │
│ │ 留下: [Hole->First ... FragFirst-1] │
│ │ [FragLast+1 ... Hole->Last] │
│ │ (若 MoreFragments 为假则右半无效) │
│ └────────────────────────────────────────┘
│
│ ├─ 无重叠 → 尝试下一个空洞
│ ├─ 有重叠 → 移除该空洞, 分裂出剩余空洞
│ │ ├─ FragFirst > Hole->First:
│ │ │ └─ 新空洞 [Hole->First, FragFirst-1]
│ │ └─ FragLast < Hole->Last && MoreFragments:
│ │ └─ 新空洞 [FragLast+1, Hole->Last]
│ │
│ ├─ 首个分片 (FragFirst == 0): 保存 IP 头
│ ├─ 创建 IP_FRAGMENT 存入 FragmentList
│ ├─ 分离 NDIS 包 (IPPacket->NdisPacket = NULL, 防止提前释放)
│ └─ 最后一个分片: IPDR->DataSize = FragFirst + Fragment->Size
│
└─ 4. 检查是否重组完成:
├─ HoleList 为空 (所有空洞被覆盖) → 组装:
│ ├─ RemoveIPDR
│ ├─ ReassembleDatagram:
│ │ ├─ 分配 TotalSize = HeaderSize + DataSize
│ │ ├─ 复制 IP 头
│ │ └─ 遍历 FragmentList, 按 Offset 拼接数据
│ ├─ IPDispatchProtocol(IF, &Datagram) // 分发上层
│ └─ Datagram.Free
│
└─ 仍有空洞 → 等待更多分片
7.4 重组超时 (IPDatagramReassemblyTimeout)
由 IP 周期计时器调用:
IPDatagramReassemblyTimeout()
├─ 遍历 ReassemblyListHead
├─ ++IPDR->TimeoutCount
└─ TimeoutCount == MAX_TIMEOUT_COUNT:
└─ 移除并 FreeIPDR (丢弃所有分片)
7.5 内存池
分片重组使用 NPAGED_LOOKASIDE_LIST 提高效率:
c
NPAGED_LOOKASIDE_LIST IPDRList; // 重组描述符池
NPAGED_LOOKASIDE_LIST IPFragmentList; // 分片描述符池
NPAGED_LOOKASIDE_LIST IPHoleList; // 空洞描述符池
8. IP 发送路径
8.1 IPTransmitPacket --- 发送入口
传输层构造 IP_PACKET (含头和数据) → IPTransmitPacket
│
├─ 填充 IPv4 头:
│ VerIHL = 0x45 (IPv4, 20 字节头)
│ Tos = 0
│ TotalLength = HeaderSize + DataSize
│ Id = TCP_IPIdentification++ (自增标识)
│ FlagsFragOfs = 0 (或 DF)
│ Ttl = 128
│ Protocol = 上层协议号
│ Checksum = IPv4Checksum(Header, HeaderSize, 0)
│ SrcAddr = 源 IP
│ DstAddr = 目的 IP
│
├─ 路由查找: 确定出接口和 NCE
│
└─ IPSendDatagram(IPPacket, NCE)
└─ SendFragments(IPPacket, NCE, NCE->Interface->MTU)
8.2 IPSendDatagram --- 发送数据报
在 transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L223-L245):
IPSendDatagram(IPPacket, NCE)
├─ 获取 PathMTU = NCE->Interface->MTU
└─ SendFragments(IPPacket, NCE, PathMTU)
9. IP 分片发送
实现在 transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c)。
9.1 分片上下文 (IPFRAGMENT_CONTEXT)
c
typedef struct _IPFRAGMENT_CONTEXT {
PNDIS_PACKET NdisPacket; // 分片发送包
PVOID Header; // IP 头
PVOID Data; // 当前分片数据位置
PNDIS_PACKET Datagram; // 原始数据报
PVOID DatagramData; // 原始数据位置
UINT HeaderSize; // IP 头大小
UINT PathMTU; // 路径 MTU
UINT Position; // 已分片位置
UINT BytesLeft; // 剩余数据
PNEIGHBOR_CACHE_ENTRY NCE; // 邻居
NDIS_STATUS Status; // 完成状态
KEVENT Event; // 同步事件
} IPFRAGMENT_CONTEXT, *PIPFRAGMENT_CONTEXT;
9.2 SendFragments --- 分片发送
在 transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L132-L221):
SendFragments(IPPacket, NCE, PathMTU)
│
├─ 分配 IFC (IPFRAGMENT_CONTEXT) + NDIS 包
├─ 复制 IP 头到 IFC->Header
├─ 初始化:
│ DatagramData = 原数据
│ HeaderSize = IP 头大小
│ PathMTU = MTU
│ BytesLeft = 数据总大小
│ Position = 0
│
├─ 循环 PrepareNextFragment(IFC):
│ ├─ 计算本片数据大小:
│ │ MaxData = PathMTU - HeaderSize
│ │ MaxData -= MaxData % 8 // 对齐到 8 字节
│ │ DataSize = MIN(BytesLeft, MaxData)
│ │ MoreFragments = (BytesLeft > MaxData)
│ │
│ ├─ 复制数据到分片包
│ ├─ 设置 FlagsFragOfs:
│ │ FragOfs = Position / 8 // 8 字节块偏移
│ │ MoreFragments → |= IPv4_MF_MASK
│ │
│ ├─ 设置 TotalLength = DataSize + HeaderSize
│ ├─ 重新计算校验和
│ └─ 更新指针 (Position += DataSize, BytesLeft -= DataSize)
│
├─ IPSendFragment(IFC->NdisPacket, NCE, IFC):
│ └─ NBQueuePacket(NCE, NdisPacket, IPSendComplete, IFC)
│ └─ 等待 IFC->Event (同步)
│
├─ 全部发送完成 → 释放 IFC 和原包
└─ 返回状态
9.3 IPSendComplete --- 分片完成回调
IPSendComplete(Context, NdisPacket, NdisStatus)
├─ IFC->Status = NdisStatus
└─ KeSetEvent(&IFC->Event) // 唤醒 SendFragments
9.4 分片示例
原始数据报: IP头(20) + 数据(3000), MTU = 1500
│
├─ 分片1: 偏移=0 MF=1 数据=1480 (1500-20, 对齐 8)
├─ 分片2: 偏移=1480 MF=1 数据=1480
└─ 分片3: 偏移=2960 MF=0 数据=40
10. 路由系统
10.1 路由表 (FIB)
实现在 router.c(file:///d:/reactos/drivers/network/tcpip/ip/network/router.c),使用 FIB (Forwarding Information Base) 结构:
FIB
├── 路由表条目 (FIB_ENTRY)
│ ├─ Target (目标网络地址)
│ ├─ Mask (掩码)
│ ├─ Router (下一跳)
│ └─ Interface (出接口)
└── 链表管理 (Insert/Remove)
10.2 核心函数
| 函数 | 功能 |
|---|---|
RouterCreateRoute(Target, Mask, Router, Interface) |
添加路由 |
RouterRemoveRoute(Target, Router) |
删除路由 |
RouterRemoveRoutesForInterface(Interface) |
删除接口所有路由 |
RouterFindRoute |
查找路由 |
RouterGetRouteTable |
导出路由表 |
RouterStartup / RouterShutdown |
初始化/清理 |
10.3 路由查找 (RouteGetRouteToDestination)
路由查找逻辑:
RouteGetRouteToDestination(Address)
│
├─ 1. 精确匹配:
│ 遍历 FIB, 查找 Target == Address 且 Mask 全覆盖
│ └─ 命中 → 使用
│
├─ 2. 最长前缀匹配:
│ 计算 Address & Mask 与 Target 匹配的所有条目
│ 选择掩码最长者
│
├─ 3. 默认路由:
│ 0.0.0.0/0 条目 (DefaultGateway)
│
└─ 4. 返回 NCE:
├─ 直连路由 → NBLocateNeighbor(Destination) 或创建
└─ 间接路由 → NBLocateNeighbor(下一跳) 或创建
10.4 接口直连路由
IPAddInterfaceRoute(IF)
├─ 添加: Target=Unicast, Mask=Netmask, Router=本机
└─ 构成直连网络路由 (如 192.168.1.0/24 via 本接口)
IPRemoveInterfaceRoute(IF)
└─ 删除上述路由
10.5 转发决策
收到的数据报目标地址不是本机时:
ProcessFragment → 检查 DstAddr 是否本机
├─ 是本机 → 分发上层协议
└─ 不是本机 → 路由器功能:
├─ 递减 TTL
├─ TTL == 0 → 发送 ICMP Time Exceeded
└─ RouteGetRouteToDestination(DstAddr)
├─ 找到 → IPTransmitPacket 转发
└─ 未找到 → 发送 ICMP Destination Unreachable
11. ICMP 协议
实现在 icmp.c(file:///d:/reactos/drivers/network/tcpip/ip/network/icmp.c)。
11.1 ICMP 报文格式
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11.2 常见类型
| Type | 含义 |
|---|---|
| 0 | Echo Reply (回显应答) |
| 3 | Destination Unreachable (目的不可达) |
| 5 | Redirect (重定向) |
| 8 | Echo Request (回显请求) |
| 11 | Time Exceeded (超时) |
11.3 核心函数
| 函数 | 功能 |
|---|---|
ICMPStartup |
注册 IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive) |
ICMPShutdown |
注销 |
ICMPReceive |
处理收到的 ICMP 报文 |
ICMPSendDatagram |
发送 ICMP 数据报 |
ICMPReply |
构造并发送 ICMP 应答 |
ICMPReceive 处理逻辑:
ICMPReceive(IF, IPPacket)
├─ 解析 ICMP 头 (Type/Code/Checksum)
├─ 验证校验和
│
├─ Type == 8 (Echo Request):
│ └─ ICMPReply(Type=0, 交换源/目的地址) // ping 应答
│
├─ Type == 3/5/11 (差错报告):
│ └─ 通知 TCP/UDP (通过事件)
│
└─ 其他 → 忽略
12. 校验和计算
12.1 校验和算法
IP/TCP/UDP 校验和都是对 16 位字累加的反码:
IPv4Checksum(Buffer, Length, Offset)
│
├─ 将数据按 16 位字累加
├─ 高 16 位进位回卷
└─ 取反 → 校验和
12.2 实现
- checksum.c(file:///d:/reactos/drivers/network/tcpip/ip/network/checksum.c) --- C 实现
- checksum.S(file:///d:/reactos/drivers/network/tcpip/ip/network/i386/checksum.S) --- x86 汇编优化(SSE/MMX)
12.3 应用场景
| 场景 | 校验对象 |
|---|---|
| IPv4 头校验 | 仅 IP 头 (HeaderSize 字节) |
| TCP 校验 | TCP 伪头 (源/目的 IP + 协议 + 长度) + TCP 段 |
| UDP 校验 | UDP 伪头 + UDP 数据报 |
| ICMP 校验 | 整个 ICMP 报文 |
13. 工作流程图
13.1 IP 接收完整流程
#mermaid-svg-m3DOL4hKxMdYrJdp{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-m3DOL4hKxMdYrJdp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-m3DOL4hKxMdYrJdp .error-icon{fill:#552222;}#mermaid-svg-m3DOL4hKxMdYrJdp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-m3DOL4hKxMdYrJdp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-m3DOL4hKxMdYrJdp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-m3DOL4hKxMdYrJdp .marker.cross{stroke:#333333;}#mermaid-svg-m3DOL4hKxMdYrJdp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-m3DOL4hKxMdYrJdp p{margin:0;}#mermaid-svg-m3DOL4hKxMdYrJdp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp .cluster-label text{fill:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp .cluster-label span{color:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp .cluster-label span p{background-color:transparent;}#mermaid-svg-m3DOL4hKxMdYrJdp .label text,#mermaid-svg-m3DOL4hKxMdYrJdp span{fill:#333;color:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp .node rect,#mermaid-svg-m3DOL4hKxMdYrJdp .node circle,#mermaid-svg-m3DOL4hKxMdYrJdp .node ellipse,#mermaid-svg-m3DOL4hKxMdYrJdp .node polygon,#mermaid-svg-m3DOL4hKxMdYrJdp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-m3DOL4hKxMdYrJdp .rough-node .label text,#mermaid-svg-m3DOL4hKxMdYrJdp .node .label text,#mermaid-svg-m3DOL4hKxMdYrJdp .image-shape .label,#mermaid-svg-m3DOL4hKxMdYrJdp .icon-shape .label{text-anchor:middle;}#mermaid-svg-m3DOL4hKxMdYrJdp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-m3DOL4hKxMdYrJdp .rough-node .label,#mermaid-svg-m3DOL4hKxMdYrJdp .node .label,#mermaid-svg-m3DOL4hKxMdYrJdp .image-shape .label,#mermaid-svg-m3DOL4hKxMdYrJdp .icon-shape .label{text-align:center;}#mermaid-svg-m3DOL4hKxMdYrJdp .node.clickable{cursor:pointer;}#mermaid-svg-m3DOL4hKxMdYrJdp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-m3DOL4hKxMdYrJdp .arrowheadPath{fill:#333333;}#mermaid-svg-m3DOL4hKxMdYrJdp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-m3DOL4hKxMdYrJdp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-m3DOL4hKxMdYrJdp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m3DOL4hKxMdYrJdp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-m3DOL4hKxMdYrJdp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m3DOL4hKxMdYrJdp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-m3DOL4hKxMdYrJdp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-m3DOL4hKxMdYrJdp .cluster text{fill:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp .cluster span{color:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp 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-m3DOL4hKxMdYrJdp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-m3DOL4hKxMdYrJdp rect.text{fill:none;stroke-width:0;}#mermaid-svg-m3DOL4hKxMdYrJdp .icon-shape,#mermaid-svg-m3DOL4hKxMdYrJdp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m3DOL4hKxMdYrJdp .icon-shape p,#mermaid-svg-m3DOL4hKxMdYrJdp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-m3DOL4hKxMdYrJdp .icon-shape .label rect,#mermaid-svg-m3DOL4hKxMdYrJdp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m3DOL4hKxMdYrJdp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-m3DOL4hKxMdYrJdp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-m3DOL4hKxMdYrJdp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ETYPE_IPv4
V4
否
是
否
是
是
否
否
是
TCP=6
UDP=17
ICMP=1
其他
LanReceiveWorker
以太网类型
IPReceive
IP 版本
IPv4Receive
解析头长度 HeaderSize
头大小合法?
丢弃
复制 IP 头
校验和正确?
丢弃
解析 SrcAddr/DstAddr/TotalSize
更新接口统计
ProcessFragment 分片处理
是完整数据报?
IPDispatchProtocol 分发
分片
查找/创建 IPDR
空洞匹配算法
空洞列表空?
等待更多分片
ReassembleDatagram 组装
协议号
TCPReceive
UDPReceive
ICMPReceive
DefaultProtocolHandler
13.2 IP 发送完整流程
#mermaid-svg-dulMdetuUDwDYLsT{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-dulMdetuUDwDYLsT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dulMdetuUDwDYLsT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dulMdetuUDwDYLsT .error-icon{fill:#552222;}#mermaid-svg-dulMdetuUDwDYLsT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dulMdetuUDwDYLsT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dulMdetuUDwDYLsT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dulMdetuUDwDYLsT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dulMdetuUDwDYLsT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dulMdetuUDwDYLsT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dulMdetuUDwDYLsT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dulMdetuUDwDYLsT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dulMdetuUDwDYLsT .marker.cross{stroke:#333333;}#mermaid-svg-dulMdetuUDwDYLsT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dulMdetuUDwDYLsT p{margin:0;}#mermaid-svg-dulMdetuUDwDYLsT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dulMdetuUDwDYLsT .cluster-label text{fill:#333;}#mermaid-svg-dulMdetuUDwDYLsT .cluster-label span{color:#333;}#mermaid-svg-dulMdetuUDwDYLsT .cluster-label span p{background-color:transparent;}#mermaid-svg-dulMdetuUDwDYLsT .label text,#mermaid-svg-dulMdetuUDwDYLsT span{fill:#333;color:#333;}#mermaid-svg-dulMdetuUDwDYLsT .node rect,#mermaid-svg-dulMdetuUDwDYLsT .node circle,#mermaid-svg-dulMdetuUDwDYLsT .node ellipse,#mermaid-svg-dulMdetuUDwDYLsT .node polygon,#mermaid-svg-dulMdetuUDwDYLsT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dulMdetuUDwDYLsT .rough-node .label text,#mermaid-svg-dulMdetuUDwDYLsT .node .label text,#mermaid-svg-dulMdetuUDwDYLsT .image-shape .label,#mermaid-svg-dulMdetuUDwDYLsT .icon-shape .label{text-anchor:middle;}#mermaid-svg-dulMdetuUDwDYLsT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dulMdetuUDwDYLsT .rough-node .label,#mermaid-svg-dulMdetuUDwDYLsT .node .label,#mermaid-svg-dulMdetuUDwDYLsT .image-shape .label,#mermaid-svg-dulMdetuUDwDYLsT .icon-shape .label{text-align:center;}#mermaid-svg-dulMdetuUDwDYLsT .node.clickable{cursor:pointer;}#mermaid-svg-dulMdetuUDwDYLsT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dulMdetuUDwDYLsT .arrowheadPath{fill:#333333;}#mermaid-svg-dulMdetuUDwDYLsT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dulMdetuUDwDYLsT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dulMdetuUDwDYLsT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dulMdetuUDwDYLsT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dulMdetuUDwDYLsT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dulMdetuUDwDYLsT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dulMdetuUDwDYLsT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dulMdetuUDwDYLsT .cluster text{fill:#333;}#mermaid-svg-dulMdetuUDwDYLsT .cluster span{color:#333;}#mermaid-svg-dulMdetuUDwDYLsT 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-dulMdetuUDwDYLsT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dulMdetuUDwDYLsT rect.text{fill:none;stroke-width:0;}#mermaid-svg-dulMdetuUDwDYLsT .icon-shape,#mermaid-svg-dulMdetuUDwDYLsT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dulMdetuUDwDYLsT .icon-shape p,#mermaid-svg-dulMdetuUDwDYLsT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dulMdetuUDwDYLsT .icon-shape .label rect,#mermaid-svg-dulMdetuUDwDYLsT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dulMdetuUDwDYLsT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dulMdetuUDwDYLsT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dulMdetuUDwDYLsT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
是
否
传输层发送
构造 IP_PACKET
填充 IPv4 头
设置 ID = 自增计数
计算头校验和
RouteGetRouteToDestination 路由查找
找到路由?
发送 ICMP 目的不可达
获取 NCE 和接口
包大小 > MTU?
IPSendDatagram 直接发送
SendFragments 分片
循环 PrepareNextFragment
设置片偏移和 MF 标志
重算校验和
NBQueuePacket 邻居排队
NCE 已解析?
Interface->Transmit
ARP 请求 → 等待
ARP 应答 → NBSendPackets
LANTransmit → NdisSend
13.3 分片重组状态图
渲染错误: Mermaid 渲染失败: Parse error on line 3: ...R] B --> C初始空洞 \[0,65536] C --> ----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'SQS'
13.4 路由查找流程
#mermaid-svg-STShIXmwGmVRrg4h{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-STShIXmwGmVRrg4h .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-STShIXmwGmVRrg4h .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-STShIXmwGmVRrg4h .error-icon{fill:#552222;}#mermaid-svg-STShIXmwGmVRrg4h .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-STShIXmwGmVRrg4h .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-STShIXmwGmVRrg4h .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-STShIXmwGmVRrg4h .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-STShIXmwGmVRrg4h .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-STShIXmwGmVRrg4h .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-STShIXmwGmVRrg4h .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-STShIXmwGmVRrg4h .marker{fill:#333333;stroke:#333333;}#mermaid-svg-STShIXmwGmVRrg4h .marker.cross{stroke:#333333;}#mermaid-svg-STShIXmwGmVRrg4h svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-STShIXmwGmVRrg4h p{margin:0;}#mermaid-svg-STShIXmwGmVRrg4h .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-STShIXmwGmVRrg4h .cluster-label text{fill:#333;}#mermaid-svg-STShIXmwGmVRrg4h .cluster-label span{color:#333;}#mermaid-svg-STShIXmwGmVRrg4h .cluster-label span p{background-color:transparent;}#mermaid-svg-STShIXmwGmVRrg4h .label text,#mermaid-svg-STShIXmwGmVRrg4h span{fill:#333;color:#333;}#mermaid-svg-STShIXmwGmVRrg4h .node rect,#mermaid-svg-STShIXmwGmVRrg4h .node circle,#mermaid-svg-STShIXmwGmVRrg4h .node ellipse,#mermaid-svg-STShIXmwGmVRrg4h .node polygon,#mermaid-svg-STShIXmwGmVRrg4h .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-STShIXmwGmVRrg4h .rough-node .label text,#mermaid-svg-STShIXmwGmVRrg4h .node .label text,#mermaid-svg-STShIXmwGmVRrg4h .image-shape .label,#mermaid-svg-STShIXmwGmVRrg4h .icon-shape .label{text-anchor:middle;}#mermaid-svg-STShIXmwGmVRrg4h .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-STShIXmwGmVRrg4h .rough-node .label,#mermaid-svg-STShIXmwGmVRrg4h .node .label,#mermaid-svg-STShIXmwGmVRrg4h .image-shape .label,#mermaid-svg-STShIXmwGmVRrg4h .icon-shape .label{text-align:center;}#mermaid-svg-STShIXmwGmVRrg4h .node.clickable{cursor:pointer;}#mermaid-svg-STShIXmwGmVRrg4h .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-STShIXmwGmVRrg4h .arrowheadPath{fill:#333333;}#mermaid-svg-STShIXmwGmVRrg4h .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-STShIXmwGmVRrg4h .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-STShIXmwGmVRrg4h .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-STShIXmwGmVRrg4h .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-STShIXmwGmVRrg4h .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-STShIXmwGmVRrg4h .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-STShIXmwGmVRrg4h .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-STShIXmwGmVRrg4h .cluster text{fill:#333;}#mermaid-svg-STShIXmwGmVRrg4h .cluster span{color:#333;}#mermaid-svg-STShIXmwGmVRrg4h 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-STShIXmwGmVRrg4h .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-STShIXmwGmVRrg4h rect.text{fill:none;stroke-width:0;}#mermaid-svg-STShIXmwGmVRrg4h .icon-shape,#mermaid-svg-STShIXmwGmVRrg4h .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-STShIXmwGmVRrg4h .icon-shape p,#mermaid-svg-STShIXmwGmVRrg4h .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-STShIXmwGmVRrg4h .icon-shape .label rect,#mermaid-svg-STShIXmwGmVRrg4h .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-STShIXmwGmVRrg4h .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-STShIXmwGmVRrg4h .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-STShIXmwGmVRrg4h :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 命中
未命中
找到
未找到
有
无
直连
间接
需要路由的目的地址
精确匹配?
使用该路由
最长前缀匹配
选择掩码最长的路由
默认路由?
使用默认路由
路由失败 → ICMP 不可达
直连?
NBLocateNeighbor 目标地址
NBLocateNeighbor 下一跳
返回 NCE
14. 数据流图
14.1 数据报接收数据流
网络接口层
│ IPReceive(IF, IPPacket)
▼
IPv4Receive
│
│ IPPacket:
│ ┌────────────────────────────┐
│ │ Header (IP 头 20B) │ ← 复制自 NDIS 包
│ │ SrcAddr / DstAddr │
│ │ TotalSize / HeaderSize │
│ │ NdisPacket (数据引用) │
│ └────────────────────────────┘
│
│ 校验和验证
▼
ProcessFragment
│
│ 分片? ── 否 ──▶ IPDispatchProtocol
│
│ 是
▼
GetReassemblyInfo (四元组匹配)
│
▼
IPDR: { Id, Src, Dst, Proto, HoleList, FragmentList }
│
│ 空洞算法: [0,65536] → [1480,65536] → [2960,65536] → 空
│
▼
ReassembleDatagram
│
│ 分配 TotalSize 缓冲
│ 复制头 + 按偏移拼接各分片
▼
IPDispatchProtocol → ProtocolTable[Protocol]
│
├─ TCPReceive / UDPReceive / ICMPReceive / RawIPReceive
▼
传输层处理
14.2 数据报发送数据流
传输层: TCPSendData / UDPSend
│
│ 构造 IP_PACKET + NDIS 包
▼
IPTransmitPacket
│
│ IPv4 头:
│ ┌────────────────────────────┐
│ │ VerIHL=0x45 TTL=128 │
│ │ Id=TCP_IPIdentification++ │
│ │ Protocol=上层协议号 │
│ │ Checksum=IPv4Checksum │
│ │ SrcAddr/DstAddr │
│ └────────────────────────────┘
▼
IPSendDatagram → SendFragments
│
│ 包 > MTU?
│ ├─ 否 → 单片段
│ └─ 是 → 分片循环:
│ │ 分片1: [0,1480) MF=1
│ │ 分片2: [1480,2960) MF=1
│ │ 分片3: [2960,3000) MF=0
▼
IPSendFragment → NBQueuePacket(NCE)
│
│ NCE 未解析 → ARP → 等待 → NBSendPackets
│
▼
NCE->Interface->Transmit
│
▼
LANTransmit (封装以太网头) → NdisSend → 网卡
14.3 转发数据流 (路由器功能)
接收数据报
│
▼
IPv4Receive → 校验通过
│
▼
ProcessFragment → 重组完成
│
▼
检查 DstAddr 是否本机?
│
├─ 是 → IPDispatchProtocol (本机处理)
│
└─ 否 (转发):
├─ TTL--
├─ TTL == 0 → ICMP Time Exceeded
├─ 重新计算校验和
├─ RouteGetRouteToDestination
│ ├─ 找到 → IPTransmitPacket (转发)
│ └─ 未找到 → ICMP Destination Unreachable
└─ 完成
15. 关键函数索引
15.1 IP 初始化与分发 (ip.c)
| 函数 | 位置 | 说明 |
|---|---|---|
IPStartup |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L407) | IP 模块初始化 |
IPShutdown |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L473) | IP 模块清理 |
IPDispatchProtocol |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L142) | 按协议号分发 |
IPRegisterProtocol |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L386) | 注册协议处理函数 |
IPRegisterInterface |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L289) | 注册接口 |
IPUnregisterInterface |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L349) | 注销接口 |
IPTimeoutDpcFn |
ip.c(file:///d:/reactos/drivers/network/tcpip/ip/network/ip.c#L112) | 周期超时 DPC |
15.2 IP 接收与重组 (receive.c)
| 函数 | 位置 | 说明 |
|---|---|---|
IPReceive |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L638) | IP 接收入口 |
IPv4Receive |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L555) | IPv4 数据报接收 |
ProcessFragment |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L271) | 分片处理 (RFC 815) |
GetReassemblyInfo |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L141) | 查找重组描述符 |
ReassembleDatagram |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L184) | 重组完整数据报 |
CreateHoleDescriptor |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L21) | 创建空洞描述符 |
FreeIPDR |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L53) | 释放重组描述符 |
IPDatagramReassemblyTimeout |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L515) | 重组超时清理 |
IPFreeReassemblyList |
receive.c(file:///d:/reactos/drivers/network/tcpip/ip/network/receive.c#L485) | 清空重组列表 |
15.3 IP 发送与分片 (transmit.c)
| 函数 | 位置 | 说明 |
|---|---|---|
IPTransmitPacket |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c) | IP 发送入口 |
IPSendDatagram |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L223) | 发送数据报 |
SendFragments |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L132) | 分片发送 |
PrepareNextFragment |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L62) | 准备下一个分片 |
IPSendFragment |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L41) | 发送单个分片 |
IPSendComplete |
transmit.c(file:///d:/reactos/drivers/network/tcpip/ip/network/transmit.c#L18) | 分片完成回调 |
15.4 路由 (router.c)
| 函数 | 位置 | 说明 |
|---|---|---|
RouterCreateRoute |
router.c(file:///d:/reactos/drivers/network/tcpip/ip/network/router.c#L451) | 添加路由 |
RouterRemoveRoute |
router.c(file:///d:/reactos/drivers/network/tcpip/ip/network/router.c#L394) | 删除路由 |
RouterRemoveRoutesForInterface |
router.c(file:///d:/reactos/drivers/network/tcpip/ip/network/router.c#L371) | 删除接口路由 |
RouterStartup / RouterShutdown |
router.c(file:///d:/reactos/drivers/network/tcpip/ip/network/router.c#L510) | 路由系统初始化/清理 |
IPAddInterfaceRoute |
ip.h(file:///d:/reactos/drivers/network/tcpip/include/ip.h#L222) | 添加接口直连路由 |
IPRemoveInterfaceRoute |
ip.h(file:///d:/reactos/drivers/network/tcpip/include/ip.h#L224) | 删除接口直连路由 |
15.5 ICMP (icmp.c)
| 函数 | 位置 | 说明 |
|---|---|---|
ICMPStartup |
icmp.c(file:///d:/reactos/drivers/network/tcpip/ip/network/icmp.c#L15) | 注册 ICMP 协议 |
ICMPShutdown |
icmp.c(file:///d:/reactos/drivers/network/tcpip/ip/network/icmp.c#L22) | 注销 |
ICMPReceive |
icmp.c(file:///d:/reactos/drivers/network/tcpip/ip/network/icmp.c#L53) | 处理 ICMP 报文 |
ICMPSendDatagram |
icmp.c(file:///d:/reactos/drivers/network/tcpip/ip/network/icmp.c#L29) | 发送 ICMP 数据报 |
ICMPReply |
icmp.c(file:///d:/reactos/drivers/network/tcpip/ip/network/icmp.c#L91) | 构造 ICMP 应答 |
15.6 校验和 (checksum.c)
| 函数 | 位置 | 说明 |
|---|---|---|
IPv4Checksum |
checksum.c(file:///d:/reactos/drivers/network/tcpip/ip/network/checksum.c) | IPv4 头校验和 |
IPv4CorrectChecksum |
checksum.c(file:///d:/reactos/drivers/network/tcpip/ip/network/checksum.c) | 验证 IPv4 校验和 |
IPv4PseudoChecksum |
checksum.c(file:///d:/reactos/drivers/network/tcpip/ip/network/checksum.c) | TCP/UDP 伪头校验和 |
IPv6PseudoChecksum |
checksum.c(file:///d:/reactos/drivers/network/tcpip/ip/network/checksum.c) | IPv6 伪头校验和 |
| 汇编优化 | checksum.S(file:///d:/reactos/drivers/network/tcpip/ip/network/i386/checksum.S) | x86 汇编实现 |
附录 A:关键头文件
| 头文件 | 路径 | 内容 |
|---|---|---|
ip.h |
include/ip.h(file:///d:/reactos/drivers/network/tcpip/include/ip.h) | IP_PACKET、IPv4_HEADER、IP_INTERFACE、协议常量 |
receive.h |
include/receive.h(file:///d:/reactos/drivers/network/tcpip/include/receive.h) | 重组结构声明 |
transmit.h |
include/transmit.h(file:///d:/reactos/drivers/network/tcpip/include/transmit.h) | 分片结构声明 |
route.h |
include/route.h(file:///d:/reactos/drivers/network/tcpip/include/route.h) | 路由查找 |
router.h |
include/router.h(file:///d:/reactos/drivers/network/tcpip/include/router.h) | 路由表管理 |
icmp.h |
include/icmp.h(file:///d:/reactos/drivers/network/tcpip/include/icmp.h) | ICMP 定义 |
checksum.h |
include/checksum.h(file:///d:/reactos/drivers/network/tcpip/include/checksum.h) | 校验和函数 |
附录 B:参考文档
- tcpip网络接口层分析(file:///d:/reactos/doc/tcpip网络接口层分析.md) --- 网络接口层 (下层)
- TCPIP 驱动分析(file:///d:/reactos/doc/TCPIP_驱动分析.md) --- tcpip.sys 整体
- TDI传输驱动接口分析(file:///d:/reactos/doc/TDI传输驱动接口分析.md) --- TDI 接口 (上层)
- RFC 791 --- Internet Protocol
- RFC 815 --- IP Datagram Reassembly Algorithms
- RFC 792 --- Internet Control Message Protocol