第 10 章 网络操作 — 10.3.3 TCP/IP驱动模块

本节剖析 TCP/IP 协议栈(tcpip.sys)的实现。 TCP/IP 是 Windows 网络协议栈的核心,实现 IP、ICMP、IGMP、TCP、UDP、ARP 等协议。ReactOS 的 TCP/IP 基于 lwIP(lightweight IP)作为内部实现,位于 [drivers/network/tcpip/tcpip/](file:///d:/reactos/drivers/network/tcpip/tcpip/) 和 [drivers/network/tcpip/ip/](file:///d:/reactos/drivers/network/tcpip/ip/)。


概述

TCP/IP 协议栈在 Windows 网络体系中的位置:

  • 上层接口:TDI(Transport Driver Interface),提供 socket-like 服务给 AFD
  • 下层接口:NDIS 协议 API,与 NDIS 库通信
  • 内部实现:lwIP 1.4.x 协议实现

本节内容概览

  • 10.3.3.0 框架图
  • 10.3.3.1 tcpip.sys 总体结构
  • 10.3.3.2 DriverEntry 与全局初始化
  • 10.3.3.3 内部结构
  • 10.3.3.4 NdisRegisterProtocol 协议注册
  • 10.3.3.5 lwIP 内核集成
  • 10.3.3.6 协议处理(IP/ICMP/ARP/TCP/UDP)
  • 10.3.3.7 NdisSend / NdisReceive 数据路径
  • 10.3.3.8 总结与代码索引

学习目标

  • 理解 TCP/IP 协议栈在网络栈中的位置
  • 掌握 tcpip.sys 的整体架构
  • 知道 lwIP 集成方式
  • 跟踪 IP 包从 NIC 到 TCP 接收端

涉及的内核子系统

子系统 头文件/源文件 核心作用
TCP/IP 主 [drivers/network/tcpip/tcpip/main.c](file:///d:/reactos/drivers/network/tcpip/tcpip/main.c) DriverEntry
TCP/IP 派发 [dispatch.c](file:///d:/reactos/drivers/network/tcpip/tcpip/dispatch.c) IRP 派发
TCP/IP 文件对象 [fileobjs.c](file:///d:/reactos/drivers/network/tcpip/tcpip/fileobjs.c) TDI 上下文
TCP/IP 信息 [info.c](file:///d:/reactos/drivers/network/tcpip/tcpip/info.c) 协议信息
ICMP [icmp.c](file:///d:/reactos/drivers/network/tcpip/tcpip/icmp.c) ICMP 处理
TCP/IP 锁 [lock.c](file:///d:/reactos/drivers/network/tcpip/tcpip/lock.c) 自旋锁
lwIP 核心 [drivers/network/tcpip/ip/](file:///d:/reactos/drivers/network/tcpip/ip/) lwIP 1.4.x 协议实现
NDIS [drivers/network/ndis/ndis/](file:///d:/reactos/drivers/network/ndis/ndis/) NDIS 库
AFD [drivers/network/afd/afd/](file:///d:/reactos/drivers/network/afd/afd/) AFD

10.3.3.0 框架图

+-------------------------------------+
| AFD (afd.sys)                       |
+-------------------------------------+
              |  TDI (IRP_MJ_*, IOCTL_TDI_*)
              v
+-------------------------------------+
| TCP/IP (tcpip.sys)                  |  本节主题
| - DriverEntry                       |
| - DispatchTdi                       |
| - 内部 lwIP 线程                    |
+-------------------------------------+
              |  NdisSend / NdisReceive
              v
+-------------------------------------+
| NDIS 库 (ndis.sys)                  |
+-------------------------------------+
              |
              v
+-------------------------------------+
| NIC Miniport                         |
+-------------------------------------+

10.3.3.1 tcpip.sys 总体结构

tcpip.sys复合协议驱动,它实现:

  1. TDI 客户端接口:暴露 \Device\Tcp\Device\Udp\Device\Ip
  2. NDIS 协议接口:通过 NDIS 接收/发送包
  3. 内部协议栈:lwIP 实现 IP/ICMP/ARP/TCP/UDP
  4. 路由表/ARP 表:维护网络状态

设备对象

tcpip.sys 暴露以下设备对象:

设备名 用途
\Device\Tcp TCP 连接
\Device\Udp UDP 数据报
\Device\Ip 原始 IP
\Device\RawIp 原始 IP(另一路径)
\Device\Icmp ICMP

10.3.3.2 DriverEntry 与全局初始化

[main.c](file:///d:/reactos/drivers/network/tcpip/tcpip/main.c):

NTSTATUS NTAPI
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    NDIS_PROTOCOL_CHARACTERISTICS ProtChars = {0};
    NDIS_HANDLE NdisProtocolHandle;
    
    // 1. 注册为 NDIS 协议驱动
    ProtChars.MajorNdisVersion = 5;
    ProtChars.OpenAdapterCompleteHandler = TCPOpenAdapterComplete;
    ProtChars.CloseAdapterCompleteHandler = TCPCloseAdapterComplete;
    ProtChars.SendCompleteHandler = TCPSendComplete;
    ProtChars.ReceiveHandler = TCPReceive;
    ProtChars.ReceiveCompleteHandler = TCPReceiveComplete;
    ProtChars.StatusHandler = TCPStatus;
    // ...
    
    NdisRegisterProtocol(&Status, &NdisProtocolHandle, &ProtChars, sizeof(ProtChars));
    
    // 2. 创建设备对象
    CreateTdiDevice(DriverObject, ...);  // \Device\Tcp, \Device\Udp 等
    
    // 3. 注册派发函数
    DriverObject->MajorFunction[IRP_MJ_CREATE] = TCPCreate;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TCPCleanup;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = TCPClose;
    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TCPDispatch;
    
    // 4. 初始化 lwIP
    LwIPInit();
    
    return STATUS_SUCCESS;
}

10.3.3.3 内部结构

tcpip.sys 内部维护以下结构:

TCPIP_GLOBALS

typedef struct _TCPIP_GLOBALS {
    // 协议字符集
    NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
    NDIS_HANDLE NdisProtocolHandle;
    
    // 适配器列表
    LIST_ENTRY AdapterList;
    
    // TCP 端点列表
    LIST_ENTRY TcpListenList;       // 监听 socket
    LIST_ENTRY TcpEstablishedList;  // 已建立连接
    LIST_ENTRY TcpClosingList;      // 关闭中
    
    // UDP 端点
    LIST_ENTRY UdpEndpointList;
    
    // lwIP 控制块
    struct tcp_pcb *TcpActivePcb;   // lwIP 主动 PCB
    
    // 锁
    FAST_MUTEX GlobalLock;
    
    // 其他
    PDRIVER_OBJECT DriverObject;
} TCPIP_GLOBALS;

10.3.3.4 NdisRegisterProtocol 协议注册

参见 10.3.2 节。tcpip.sys 也是 NDIS 协议驱动,注册时使用 NdisRegisterProtocol

注册后通过 NdisOpenAdapter 绑定 NIC:

NDIS_STATUS TCPOpenAdapter(NDIS_HANDLE NdisBindingContext, NDIS_HANDLE ProtocolBindingContext,
                            PNDIS_OPEN_BLOCK OpenBlock, PNDIS_BIND_PARAMETERS BindParameters)
{
    // 1. 创建适配器结构
    PTCPIP_ADAPTER Adapter = ExAllocatePoolWithTag(NonPagedPool, sizeof(TCPIP_ADAPTER), 'pctT');
    
    // 2. 记录绑定的 NIC
    Adapter->BindingHandle = BindParameters->BindingHandle;
    
    // 3. 分配包池、缓冲池
    NdisAllocatePacketPool(&Status, &Adapter->PacketPool, 64, 0);
    NdisAllocateBufferPool(&Status, &Adapter->BufferPool, 64);
    
    // 4. 加入适配器列表
    InsertHeadList(&GlobalAdapterList, &Adapter->ListEntry);
    
    return NDIS_STATUS_SUCCESS;
}

10.3.3.5 lwIP 内核集成

ReactOS 在 tcpip.sys嵌入 lwIP(一个轻量级 TCP/IP 实现)。集成方式:

lwIP 关键文件

[drivers/network/tcpip/ip/](file:///d:/reactos/drivers/network/tcpip/ip/) 包含:

  • src/core/ipv4/ip4.c:IPv4
  • src/core/inet_chksum.c:校验和
  • src/core/tcp_in.ctcp_out.c:TCP 输入输出
  • src/core/udp.c:UDP
  • src/core/mem.cpbuf.c:内存管理
  • src/netif/etharp.c:ARP
  • src/api/tcp_api.cudp_api.c:BSD-like API

线程模型

lwIP 在单线程模型下设计,但 ReactOS 在内核中运行。ReactOS 使用 线程同步机制

  • 全局锁LwIPLock 保护 lwIP 数据结构
  • 事件LwIPEvent 唤醒等待线程
  • pbuf 自旋锁LwIPpbufLock 保护缓冲区

内存管理

tcpip.sys 提供 NT 内核包装的内存分配:

// 替换 lwIP 的内存函数
void *tcpip_alloc(size_t size) {
    return ExAllocatePoolWithTag(NonPagedPool, size, 'piwL');
}

10.3.3.6 协议处理

IP 层

ip4_input 接收包并路由:

// lwIP 内部
err_t ip4_input(struct pbuf *p, struct netif *inp) {
    // 1. 解析 IP 头
    struct ip_hdr *iphdr = p->payload;
    
    // 2. 校验和验证
    if (ip4_csum(iphdr) != 0) {
        pbuf_free(p);
        return ERR_OK;
    }
    
    // 3. 检查目标 IP
    if (ip4_addr_cmp(&iphdr->dest, &inp->ip_addr)) {
        // 目标 IP 属于本 NIC
        // 根据协议分发
        switch (iphdr->_proto) {
            case IP_PROTO_TCP:
                tcp_input(p, inp);
                break;
            case IP_PROTO_UDP:
                udp_input(p, inp);
                break;
            case IP_PROTO_ICMP:
                icmp_input(p, inp);
                break;
        }
    }
}

TCP 连接

tcpip.sys 中 TCP 连接的建立(三次握手)通过 lwIP 的 tcp_connecttcp_listentcp_accept 实现。

UDP 数据报

udp_input 接收 UDP 报文,匹配目的端口的端点,复制数据给应用。

ICMP

icmp_input 处理 ping、traceroute、错误报告。

ARP

etharp_input 维护 IP → MAC 映射表,必要时构造 ARP 请求。


10.3.3.7 NdisSend / NdisReceive 数据路径

发送

tcpip.sys 发送 IP 包到 NDIS:

NDIS_STATUS TCPSend(NDIS_HANDLE NdisBindingContext, PNDIS_PACKET Packet) {
    PTCPIP_ADAPTER Adapter = NdisBindingContext;
    
    // 调用 NDIS 协议 API
    NdisSend(&Status, Adapter->BindingHandle, Packet);
    
    return Status;
}

接收

INT TCPReceive(NDIS_HANDLE ProtocolBindingContext, NDIS_HANDLE MacReceiveContext,
               UCHAR HeaderBuffer[], UINT HeaderBufferSize,
               UCHAR LookaheadBuffer[], UINT LookaheadBufferSize, UINT PacketSize)
{
    PTCPIP_ADAPTER Adapter = ProtocolBindingContext;
    
    // 1. 检查包长度
    if (PacketSize == 0) {
        return 0;
    }
    
    // 2. 构造 pbuf
    struct pbuf *p = pbuf_alloc(PBUF_RAW, PacketSize, PBUF_POOL);
    RtlCopyMemory(p->payload, LookaheadBuffer, LookaheadBufferSize);
    
    // 3. 提交给 lwIP
    Adapter->NetifInput(p, Adapter->Netif);  // = ip4_input
    
    return LookaheadBufferSize;
}

10.3.3.8 总结

关键要点

  1. tcpip.sys 是 NDIS 协议驱动 + TDI 提供者
  2. TDI 接口\Device\Tcp\Device\Udp
  3. NDIS 接口:通过 NdisSend / NdisReceive 与 NIC 通信
  4. lwIP 集成:作为内部协议实现
  5. 协议处理:IP/ICMP/ARP/TCP/UDP 完整 IPv4
  6. 线程安全:全局锁保护 lwIP 数据
  7. 不支持 IPv6(当前实现)

TCP/IP 协议栈的深度技术分析

ReactOS 的 TCP/IP 协议栈(tcpip.sys)是整个网络体系中最复杂的组件之一。它同时扮演两个角色:作为 NDIS 协议驱动与底层 NIC 通信,作为 TDI 提供者向上层(AFD)暴露传输层服务。本节深入分析其内部架构和实现细节。

tcpip.sys 的双重身份

tcpip.sys 的设计独特之处在于它同时实现了两个标准接口:

  1. NDIS 协议接口:通过 NdisRegisterProtocol 注册为 NDIS 协议驱动,使用 NdisSend 发送数据包,通过 ProtocolReceive 回调接收数据包。这使得 tcpip.sys 可以直接与 NDIS 库交互,无需中间层。

  2. TDI 接口:通过创建设备对象(\Device\Tcp\Device\Udp\Device\Ip)和处理 TDI IOCTL 请求,向上层驱动(主要是 AFD)提供传输层服务。

这种双重身份的设计使得 tcpip.sys 可以直接控制从网络层到数据链路层的完整数据路径,减少了中间层的开销。

DriverEntry 的完整初始化流程

tcpip.sysDriverEntry(位于 main.c)执行以下关键初始化步骤:

  1. 全局变量初始化:初始化设备对象指针(TCPDeviceObjectUDPDeviceObjectIPDeviceObject)、包池句柄、缓冲池句柄等。

  2. NDIS 协议注册:调用 NdisRegisterProtocol 注册为 NDIS 协议驱动,提供接收回调(TCPReceiveTCPReceiveComplete)和状态回调。

  3. TDI 设备创建:为每种协议类型创建独立的设备对象:

    • \Device\Tcp:处理 TCP 连接请求
    • \Device\Udp:处理 UDP 数据报请求
    • \Device\Ip:处理原始 IP 请求
    • \Device\RawIp:处理原始 IP(另一路径)
  4. IRP 派发函数注册:注册 IRP_MJ_CREATEIRP_MJ_CLOSEIRP_MJ_CLEANUPIRP_MJ_INTERNAL_DEVICE_CONTROL 的处理函数。

  5. lwIP 初始化:调用 LwIPInit 初始化 lwIP 协议栈,包括内存池、定时器、网络接口等。

  6. 网络定时器:初始化 IP 分片重组定时器(IPTimer)和超时 DPC(IPTimeoutDpc)。

TDI 请求处理机制

TDI(Transport Driver Interface)请求通过 IRP_MJ_INTERNAL_DEVICE_CONTROL 传递到 tcpip.sysdispatch.c 中的 DispatchTdi 函数是 TDI 请求的主派发器:

NTSTATUS DispatchTdi(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
    ULONG IoControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
    
    switch (IoControlCode) {
        case IOCTL_TDI_ASSOCIATE_ADDRESS:
            // 关联地址到连接
            break;
        case IOCTL_TDI_CONNECT:
            // 建立连接(TCP 三次握手)
            break;
        case IOCTL_TDI_DISCONNECT:
            // 断开连接(TCP 四次挥手)
            break;
        case IOCTL_TDI_SEND:
            // 发送数据(TCP)
            break;
        case IOCTL_TDI_RECEIVE:
            // 接收数据(TCP)
            break;
        case IOCTL_TDI_SEND_DATAGRAM:
            // 发送数据报(UDP)
            break;
        case IOCTL_TDI_RECEIVE_DATAGRAM:
            // 接收数据报(UDP)
            break;
        // ... 更多 TDI IOCTL
    }
}

每个 TDI IOCTL 对应一个特定的传输层操作。TDI 的设计使得上层驱动(AFD)无需知道底层是 TCP 还是 UDP——它只需要打开正确的设备对象并发送对应的 IOCTL。

文件对象与端点管理

tcpip.sys 使用文件对象(FILE_OBJECT)来表示传输端点。当 AFD 调用 ZwCreateFile 打开 \Device\Tcp 时,TCPCreate 函数分配一个上下文结构,关联到文件对象的 FsContext 字段:

NTSTATUS TCPCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    // 分配端点上下文
    PTCP_ENDPOINT Endpoint = ExAllocatePoolWithTag(NonPagedPool, 
                                                    sizeof(TCP_ENDPOINT), 'pctT');
    
    // 关联到文件对象
    IrpSp->FileObject->FsContext = Endpoint;
    
    // 初始化端点
    Endpoint->State = TCP_STATE_CLOSED;
    Endpoint->DeviceObject = DeviceObject;
    
    return STATUS_SUCCESS;
}

这种设计使得每个 socket 连接都有独立的文件对象和端点上下文,便于管理和跟踪。

lwIP 集成的详细架构

ReactOS 使用 lwIP(lightweight IP)作为 TCP/IP 协议栈的内部实现。lwIP 的集成涉及以下几个关键方面:

  1. 代码组织:lwIP 源码位于 drivers/network/tcpip/lwip/src/ 目录,包括核心协议实现(core/)、网络接口(netif/)和应用 API(api/)。ReactOS 的适配代码位于 drivers/network/tcpip/ip/ 目录。

  2. 系统抽象层:lwIP 需要操作系统提供定时器、线程同步、消息队列等功能。ReactOS 在 sys_arch.c 中实现了这些抽象:

    • sys_arch_mbox_new:创建消息邮箱(使用 KeInitializeQueue
    • sys_arch_sem_new:创建信号量(使用 KeInitializeSemaphore
    • sys_arch_timeouts:获取超时链表
  3. 内存适配:lwIP 的 mem_mallocmem_free 被替换为使用 NT 内核分配器的版本:

    void *tcpip_alloc(size_t size) {
        return ExAllocatePoolWithTag(NonPagedPool, size, 'piwL');
    }
    
  4. 网络接口桥接:lwIP 的 netif 结构与 NDIS 适配器绑定。ip.c 中的 lwip_glue 模块实现了 NDIS 到 lwIP 的桥接:

    • netif_set_linkoutput:设置链路层输出函数
    • tcpip_input:将 NDIS 接收的包传递给 lwIP

pbuf(Packet Buffer)管理

lwIP 使用 pbuf 结构管理网络数据包。pbuf 是一个链式结构,每个节点包含一个数据缓冲区和指向下一个节点的指针:

struct pbuf {
    struct pbuf *next;    // 下一个 pbuf
    void *payload;        // 数据指针
    u16_t tot_len;        // 总长度(包括后续 pbuf)
    u16_t len;            // 本 pbuf 数据长度
    u8_t type;            // 类型(RAM/ROM/REF/POOL)
    u8_t flags;
    u16_t ref;            // 引用计数
};

pbuf 的类型决定了内存管理方式:

  • PBUF_RAM:数据在连续内存中,可修改
  • PBUF_ROM:数据在只读内存中
  • PBUF_REF:引用外部数据,不拥有所有权
  • PBUF_POOL:从预分配池中分配,用于快速路径

在 ReactOS 中,从 NDIS 接收的数据包通常需要复制到 pbuf 中,因为 NDIS 和 lwIP 使用不同的缓冲区管理方式。

TCP 连接的完整生命周期

TCP 连接在 tcpip.sys 中的完整生命周期如下:

  1. 创建端点:AFD 通过 ZwCreateFile(\Device\Tcp) 创建文件对象,TCPCreate 分配 TCP_ENDPOINT

  2. 关联地址:AFD 发送 IOCTL_TDI_ASSOCIATE_ADDRESS,将端点绑定到本地地址和端口。lwIP 创建 tcp_pcb(Protocol Control Block)。

  3. 建立连接:AFD 发送 IOCTL_TDI_CONNECT,lwIP 调用 tcp_connect 发送 SYN 包。三次握手完成后,端点状态变为 ESTABLISHED

  4. 数据传输:AFD 发送 IOCTL_TDI_SEND,lwIP 调用 tcp_write 将数据放入发送队列。tcp_output 根据拥塞窗口和接收窗口决定发送时机。

  5. 数据接收:lwIP 的 tcp_input 收到数据后,通过回调通知 tcpip.systcpip.sys 将数据放入端点的接收队列,完成挂起的 IOCTL_TDI_RECEIVE IRP。

  6. 断开连接:AFD 发送 IOCTL_TDI_DISCONNECT,lwIP 调用 tcp_close 发送 FIN 包。四次挥手完成后,端点状态变为 CLOSED

  7. 清理:AFD 调用 ZwClose 关闭文件对象,TCPClose 释放端点资源。

ARP 表的维护

ARP(Address Resolution Protocol)在 tcpip.sys 中通过 lwIP 的 etharp 模块实现。ARP 表维护 IP 地址到 MAC 地址的映射:

// ARP 表项结构
struct etharp_entry {
    ip_addr_t ipaddr;      // IP 地址
    struct eth_addr ethaddr; // MAC 地址
    u8_t state;            // 状态(EMPTY/PENDING/STABLE)
    struct timer timer;    // 超时定时器
};

当需要发送 IP 包时,etharp_output 查找 ARP 表:

  • 如果找到匹配的表项,直接使用 MAC 地址发送
  • 如果未找到,发送 ARP 请求并将 IP 包排队等待
  • 收到 ARP 响应后,更新 ARP 表并发送排队的 IP 包

ARP 表项有超时机制(默认 5 分钟),过期后需要重新解析。

IP 分片与重组

tcpip.sys 支持 IP 分片重组。当收到的 IP 数据报被分片时,ip4_reass 函数负责重组:

  1. 为每个分片组分配重组缓冲区
  2. 将分片按偏移量插入缓冲区
  3. 当所有分片到达时,组装完整数据报
  4. 如果超时(默认 60 秒),丢弃不完整的分片组

发送方向的 IP 分片由 ip4_frag 处理,当数据报大于 MTU 时自动分片。

与 Windows tcpip.sys 的对比

特性 Windows tcpip.sys ReactOS tcpip.sys
协议栈来源 微软专有实现 lwIP 开源实现
IPv6 完整支持 代码存在但未启用
TCP 窗口缩放 支持 lwIP 支持
TCP 时间戳 支持 lwIP 支持
校验和卸载 支持 部分支持
接收端合并 支持 不支持
多队列 支持 不支持
WFP 集成 深度集成 不支持

ReactOS 的 tcpip.sys 虽然在功能上不如 Windows 完整,但已经能够处理大多数常见的网络场景。lwIP 的模块化设计使得未来可以逐步添加新特性,如 IPv6 支持、TCP 卸载等。


本章代码索引

文件 内容
[main.c](file:///d:/reactos/drivers/network/tcpip/tcpip/main.c) DriverEntry
[dispatch.c](file:///d:/reactos/drivers/network/tcpip/tcpip/dispatch.c) IRP 派发
[fileobjs.c](file:///d:/reactos/drivers/network/tcpip/tcpip/fileobjs.c) TDI 文件对象
[info.c](file:///d:/reactos/drivers/network/tcpip/tcpip/info.c) 协议信息
[icmp.c](file:///d:/reactos/drivers/network/tcpip/tcpip/icmp.c) ICMP
[lock.c](file:///d:/reactos/drivers/network/tcpip/tcpip/lock.c)
[ip/](file:///d:/reactos/drivers/network/tcpip/ip/) lwIP 协议实现
[afd/afd/](file:///d:/reactos/drivers/network/afd/afd/) AFD
[ndis/](file:///d:/reactos/drivers/network/ndis/ndis/) NDIS 库

更多推荐