tcpip.sys 网络层 (IP) 详细分析

tcpip.sys 网络层 (IP) 详细分析

目录

  1. 概述
  2. [IP 层整体架构](#IP 层整体架构)
  3. [IPv4 报文格式](#IPv4 报文格式)
  4. [IP 数据包结构 (IP_PACKET)](#IP 数据包结构 (IP_PACKET))
  5. 协议表与分发机制
  6. [IP 接收路径](#IP 接收路径)
  7. [IP 分片重组 (RFC 815)](#IP 分片重组 (RFC 815))
  8. [IP 发送路径](#IP 发送路径)
  9. [IP 分片发送](#IP 分片发送)
  10. 路由系统
  11. [ICMP 协议](#ICMP 协议)
  12. 校验和计算
  13. 工作流程图
  14. 数据流图
  15. 关键函数索引

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 核心职责

  1. 数据报接收:验证 IP 头、校验和、分片重组、按协议号分发
  2. 数据报发送:路由选择、MTU 分片、交付网络接口层
  3. 路由转发:目的地址不在本机时转发到下一跳
  4. ICMP 支持:差错报告(目的不可达等)和回显(ping)
  5. 地址管理:接口 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
相关推荐
草莓熊Lotso1 小时前
【Linux网络】从0手写Reactor反应堆(二):完善核心细节——ET非阻塞读写、分层架构与回调机制
linux·运维·服务器·网络·c++·tcp/ip·架构
驱动探索者1 小时前
RISC-V 指令集深度解析:从 ISA 到 Zephyr
网络·计算机·操作系统·os
wuhuhuan2 小时前
Day17:HTTP 接口测试与链式调用 — sendRequest 从入门到实战
网络·网络协议·http
showyoui2 小时前
K8s 集群迁移踩坑:Istio 升级后 nginx 403
网络·docker·kubernetes·istio·service_mesh
执笔画流年呀2 小时前
网络原理(http)(https)
网络·http·https
m0_547486662 小时前
《网络协议安全》全套PPT课件(太原理工大学)
网络协议·安全·网络安全
caimouse2 小时前
tcpip.sys 传输层 (TCP) 详细分析
网络·网络协议·tcp/ip
SendTomo3 小时前
send.wang私传网:P2P直连传大文件首选工具
javascript·网络·网络协议·webrtc·p2p
llllll1523 小时前
HTTP协议全解:从报文结构到HTTPS加密原理
网络协议·http·https