TCP/IP 协议驱动分析:用户态 Winsock → TDI → DeviceIoControl 调用链

TCP/IP 协议驱动分析:用户态 Winsock → TDI → DeviceIoControl 调用链

目录

  1. 概述
  2. 完整调用链架构
  3. [用户态 Winsock 层](#用户态 Winsock 层)
  4. [WSP 服务提供者架构](#WSP 服务提供者架构)
  5. [内核态 AFD.sys 辅助功能驱动](#内核态 AFD.sys 辅助功能驱动)
  6. [TDI 传输驱动接口](#TDI 传输驱动接口)
  7. [DeviceIoControl 内核机制](#DeviceIoControl 内核机制)
  8. 典型操作调用链分析
  9. 工作流程图
  10. 数据流图
  11. 关键函数索引

1. 概述

本部分分析从用户态 Winsock API内核态 TCP/IP 协议栈 的完整调用路径。一个应用程序调用 send()/recv()/connect() 等网络函数时,数据请求会依次穿过以下层次:

复制代码
应用程序 (App.exe)
    │
    ▼
Winsock 用户态库 (ws2_32.dll)          ← 用户态 API 入口
    │
    ▼
WSP 服务提供者 (AFD Provider)           ← 通过 DeviceIoControl 进入内核
    │
    ▼
AFD.sys (辅助功能驱动)                  ← 内核态 socket 语义实现
    │
    ▼
TDI (传输驱动接口)                      ← 内核态网络接口标准
    │
    ▼
tcpip.sys (TCP/IP 协议驱动)             ← 真正的协议实现
    │
    ▼
NDIS 库 (ndis.sys) → 网卡驱动

三个关键转换点:

转换点 内容
用户态 → 内核态 Winsock 通过 DeviceIoControl()\Device\Afd 设备发起 IOCTL,产生 IRP_MJ_DEVICE_CONTROL IRP
AFD → TDI AFD 将 IOCTL_AFD_* 翻译为 TDI 操作(TDI_CONNECTTDI_SEND 等),以 IRP_MJ_INTERNAL_DEVICE_CONTROL IRP 发给 \Device\Tcp/\Device\Udp
TDI → 协议栈 tcpip.sys 的 TiDispatchInternal 分发处理 TDI 请求

2. 完整调用链架构

2.1 分层总览

复制代码
┌─────────────────────────────────────────────────────────────────┐
│  用户模式 (Ring 3)                                               │
│                                                                 │
│  ┌──────────────┐   ┌──────────────────┐   ┌─────────────────┐  │
│  │ 应用程序      │   │ ws2_32.dll      │   │ 服务提供者 DLL    │  │
│  │ (App.exe)    │──▶│ (Winsock API)   │──▶│ (AFD Provider)  │  │
│  │ socket()     │   │ WSP 分发/调度    │   │ msafd/自实现    │  │
│  │ send/recv    │   │ 句柄→WSSOCKET   │   │ 组织 IOCTL 缓冲  │  │
│  └──────────────┘   └──────────────────┘   └────────┬────────┘  │
│                                                      │           │
│                                     NtDeviceIoControlFile/      │
│                                     DeviceIoControl             │
└──────────────────────────────────────────────────────┬──────────┘
                                                       │ IRP_MJ_DEVICE_CONTROL
                                                       ▼
┌─────────────────────────────────────────────────────────────────┐
│  内核模式 (Ring 0)                                               │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐   │
│  │ AFD.sys --- \Device\Afd (辅助功能驱动)                        │   │
│  │                                                           │   │
│  │  AfdDispatch() ──switch(IOCTL_AFD_*)──▶ 各处理函数        │   │
│  │  │  IOCTL_AFD_CONNECT      → AfdStreamSocketConnect      │   │
│  │  │  IOCTL_AFD_SEND         → AfdConnectedSocketWriteData │   │
│  │  │  IOCTL_AFD_RECV         → AfdConnectedSocketReadData  │   │
│  │  │  IOCTL_AFD_BIND         → AfdBindSocket               │   │
│  │  │  IOCTL_AFD_START_LISTEN → AfdListenSocket             │   │
│  │  │  IOCTL_AFD_SELECT       → AfdSelect                   │   │
│  │  │  ... (40+ 个 IOCTL)                                   │   │
│  │  │                                                       │   │
│  │  │  AFD_FCB (FileObject->FsContext) = 每个 socket 的状态   │   │
│  │  └──────────────────────────┬────────────────────────────┘   │
│  │                             │ tdihelpers (TdiXxx)            │
│  │                             ▼                                │
│  │  ┌───────────────────────────────────────────────────────┐   │
│  │  │ TDI 调用 → IRP_MJ_INTERNAL_DEVICE_CONTROL              │   │
│  │  │   TdiConnect     → \Device\Tcp (TDI_CONNECT)          │   │
│  │  │   TdiSend        → \Device\Tcp (TDI_SEND)             │   │
│  │  │   TdiReceive     → \Device\Tcp (TDI_RECEIVE)          │   │
│  │  │   TdiOpenAddressFile → \Device\Udp (带 EA 的 CREATE)   │   │
│  │  └──────────────────────────┬────────────────────────────┘   │
│  │                             ▼                                │
│  │  ┌───────────────────────────────────────────────────────┐   │
│  │  │ tcpip.sys --- \Device\Tcp / \Device\Udp                 │   │
│  │  │  TiDispatchInternal() ──switch(MinorFunction)──▶      │   │
│  │  │    TDI_CONNECT         → DispTdiConnect               │   │
│  │  │    TDI_SEND            → DispTdiSend                  │   │
│  │  │    TDI_RECEIVE         → DispTdiReceive               │   │
│  │  │    TDI_QUERY_INFORMATION→ DispTdiQueryInformation     │   │
│  │  └──────────────────────────┬────────────────────────────┘   │
│  │                             ▼                                │
│  │                     TCP/UDP/IP/ARP/路由实现                   │
│  │                             ▼                                │
│  │                     NDIS 协议接口 (lan.c)                    │
│  └───────────────────────────────────────────────────────────┘   │
│                             │ NdisSend / NdisRequest            │
│                             ▼                                   │
│                      ndis.sys → 微型端口 → 硬件                  │
└─────────────────────────────────────────────────────────────────┘

2.2 两种 IOCTL 路径的区分

调用链中存在两级 IOCTL,容易混淆:

级别 发起者 接收者 IRP 类型 设备对象
用户态→AFD 用户态 WSP 提供者 AFD.sys IRP_MJ_DEVICE_CONTROL \Device\Afd
AFD→传输驱动 AFD.sys (内核) tcpip.sys IRP_MJ_INTERNAL_DEVICE_CONTROL \Device\Tcp/\Device\Udp

区别要点:

  • IRP_MJ_DEVICE_CONTROL:可从用户态通过 DeviceIoControl 直接发起
  • IRP_MJ_INTERNAL_DEVICE_CONTROL:只能在内核态通过 IoBuildDeviceIoControlRequest/TdiBuildInternalDeviceControlIrp 发起,用于驱动间通信

3. 用户态 Winsock 层

3.1 ws2_32.dll 的架构

ReactOS 的 ws2_32.dll 位于 d:\reactos\dll\win32\ws2_32\,是一个 Winsock 2 API 实现 ,采用 WSP (Winsock Service Provider) 架构

复制代码
ws2_32.dll
├── startup.c      --- WSAStartup/WSACleanup 初始化
├── socklife.c     --- socket/closesocket 生命周期管理
├── sockctrl.c     --- connect/listen/getsockopt/setsockopt/ioctlsocket
├── send.c / recv.c --- send/recv/sendto/recvfrom
├── select.c       --- select/WSAPoll
├── event.c        --- WSAEventSelect
├── dprovide.c     --- LoadLibrary + WSPStartup 加载服务提供者
├── dcatalog.c     --- Winsock 服务目录管理
├── addrinfo.c     --- getaddrinfo 等名称解析
└── ...

3.2 关键机制:WSSOCKET 上下文

每个 socket 句柄在 ws2_32 中对应一个 WSSOCKET 上下文结构,包含:

c 复制代码
typedef struct _WSSOCKET {
    SOCKET Sock;                    // 原生的 socket 句柄
    PVOID Provider;                 // 指向服务提供者的指针
    BOOL NonBlocking;               // 非阻塞标记
    ...
} WSSOCKET, *PWSSOCKET;

当应用调用 connect() 时,ws2_32 通过 WsSockGetSocket(s) 查找句柄对应的 WSSOCKET,然后调用其绑定的服务提供者:

c 复制代码
Status = Socket->Provider->Service.lpWSPConnect(   // WSP 调用
                 s, name, namelen, NULL, NULL, NULL, NULL, &ErrorCode);

所有 Winsock 2 API 都遵循这个模式:ws2_32 只做参数验证、句柄查找和错误处理,真正的工作委托给服务提供者

3.3 WSAStartup 初始化流程

复制代码
WSAStartup() → WsApiProlog()
   │
   ├─ 检查进程内是否已初始化
   ├─ 枚举 Winsock 服务目录 (WSCEnumProtocols)
   ├─ 按优先级选择默认服务提供者
   └─ 返回 WSADATA (版本 2.2)

4. WSP 服务提供者架构

4.1 服务提供者加载

dprovide.c(file:///d:/reactos/dll/win32/ws2_32/src/dprovide.c) 中,LoadTransportProviders 负责加载服务提供者:

复制代码
LoadTransportProviders()
   │
   ├─ WSCEnumProtocols() 枚举已安装的协议目录
   ├─ 对每个提供者:
   │    ├─ LoadLibrary(ProviderDll)         ← 加载提供者 DLL
   │    ├─ GetProcAddress(..., "WSPStartup") ← 获取入口
   │    └─ WSPStartup()                     ← 初始化提供者
   ├─ 建立 SOCKET → Provider 映射表
   └─ 返回提供者列表

4.2 WSP 函数表

服务提供者通过 WSPStartup 导出 WSPUPCALLTABLE 和自身的 WSPPROC_TABLE。ws2_32 调用 lpWSPConnectlpWSPSendlpWSPRecv 等函数指针。

4.3 AFD 服务提供者的职责

在标准 Windows 架构中,msafd.dll(在 ReactOS 中为 mswsock.dll 的 AFD 提供者)是默认的 Winsock 服务提供者,其核心职责是:

  1. 维护内核句柄socket() 时通过 CreateFile("\Device\Afd") 获取内核文件句柄
  2. 组织 IOCTL 缓冲 :将 WSP 调用的参数(sockaddr、WSABUF 数组、标志)填入 AFD_* 结构
  3. 发起 DeviceIoControl :调用 NtDeviceIoControlFile 将请求送进内核
  4. 处理完成事件:通过事件对象接收内核完成通知

ReactOS 现状 :当前 mswsock.dll 的 AFD 提供者部分仍是 stub,AFD.sys 本身已实现了完整的 IOCTL 接口,等待用户态提供者对接。


5. 内核态 AFD.sys 辅助功能驱动

5.1 设备与分发

AFD.sys 位于 d:\reactos\drivers\network\afd\,源码入口在 main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L1318-L1359)。

DriverEntry 关键动作:

c 复制代码
UNICODE_STRING wstrDeviceName = RTL_CONSTANT_STRING(L"\\Device\\Afd");
...
// 注册所有 MajorFunction 到统一分发
DriverObject->MajorFunction[IRP_MJ_CLOSE]          = AfdDispatch;
DriverObject->MajorFunction[IRP_MJ_CREATE]         = AfdDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP]        = AfdDispatch;
DriverObject->MajorFunction[IRP_MJ_WRITE]          = AfdDispatch;
DriverObject->MajorFunction[IRP_MJ_READ]           = AfdDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatch;
...
// 创建设备对象 (FILE_DEVICE_NAMED_PIPE 类型)
IoCreateDevice(DriverObject, sizeof(AFD_DEVICE_EXTENSION),
               &wstrDeviceName, FILE_DEVICE_NAMED_PIPE,
               0, FALSE, &DeviceObject);

AFD_DEVICE_EXTENSION 结构:

c 复制代码
typedef struct _AFD_DEVICE_EXTENSION {
    PDEVICE_OBJECT DeviceObject;   // 指向本设备对象
    LIST_ENTRY Polls;              // 活跃 select/poll 请求链表
    KSPIN_LOCK Lock;               // 保护 Polls 链表
} AFD_DEVICE_EXTENSION, *PAFD_DEVICE_EXTENSION;

5.2 AFDDispatch 统一分发

所有 IRP 都由 AfdDispatch(file:///d:/reactos/drivers/network/afd/afd/main.c#L906-L1094) 处理:

复制代码
IRP_MJ_CREATE           → AfdCreateSocket      (创建 socket 上下文)
IRP_MJ_CLOSE            → AfdCloseSocket       (关闭 socket)
IRP_MJ_CLEANUP          → AfdCleanupSocket     (清理挂起的 IRP)
IRP_MJ_WRITE            → AfdConnectedSocketWriteData
IRP_MJ_READ             → AfdConnectedSocketReadData
IRP_MJ_DEVICE_CONTROL   → switch(IoControlCode)

IRP_MJ_DEVICE_CONTROL 的 IOCTL 分发表(核心):

IOCTL 代码 处理函数 对应 Winsock API
IOCTL_AFD_BIND AfdBindSocket bind()
IOCTL_AFD_CONNECT AfdStreamSocketConnect connect() (阻塞)
IOCTL_AFD_SUPER_CONNECT AfdStreamSocketSuperConnect ConnectEx()
IOCTL_AFD_START_LISTEN AfdListenSocket listen()
IOCTL_AFD_WAIT_FOR_LISTEN AfdWaitForListen accept() 前等待
IOCTL_AFD_ACCEPT AfdAccept accept()
IOCTL_AFD_RECV AfdConnectedSocketReadData recv()
IOCTL_AFD_RECV_DATAGRAM AfdPacketSocketReadData recvfrom()
IOCTL_AFD_SEND AfdConnectedSocketWriteData send()
IOCTL_AFD_SEND_DATAGRAM AfdPacketSocketWriteData sendto()
IOCTL_AFD_SELECT AfdSelect select()
IOCTL_AFD_EVENT_SELECT AfdEventSelect WSAEventSelect()
IOCTL_AFD_ENUM_NETWORK_EVENTS AfdEnumEvents WSAEnumNetworkEvents()
IOCTL_AFD_DISCONNECT AfdDisconnect shutdown()/closesocket()
IOCTL_AFD_GET_INFO AfdGetInfo getsockopt() 部分
IOCTL_AFD_SET_INFO AfdSetInfo setsockopt() 部分
IOCTL_AFD_GET_SOCK_NAME AfdGetSockName getsockname()
IOCTL_AFD_GET_PEER_NAME AfdGetPeerName getpeername()
IOCTL_AFD_GET_TDI_HANDLES AfdGetTdiHandles 诊断工具 (netstat)

5.3 AFD_FCB:每个 socket 的内核状态

AFD 使用 FCB (File Control Block) 保存每个 socket 的完整状态,存放在 FileObject->FsContext 中:

c 复制代码
typedef struct _AFD_FCB {
    BOOLEAN Locked, Critical, NonBlocking, OobInline;
    BOOLEAN TdiReceiveClosed, SendClosed;
    ...
    AFD_TDI_OBJECT AddressFile;          // TDI 地址文件对象 (句柄+文件对象)
    AFD_TDI_OBJECT Connection;           // TDI 连接端点对象
    UNICODE_STRING TdiDeviceName;        // 传输设备名 (如 \Device\Tcp)
    AFD_TDI_OBJECT AcceptQueue;          // 接受队列
    AFD_IN_FLIGHT_REQUEST ConnectIrp;    // 进行中的 TDI_CONNECT IRP
    AFD_IN_FLIGHT_REQUEST ReceiveIrp;    // 进行中的 TDI_RECEIVE IRP
    AFD_IN_FLIGHT_REQUEST SendIrp;       // 进行中的 TDI_SEND IRP
    PIRP PendingIrpList[MAX_FUNCTIONS];  // 各功能挂起的用户 IRP
    AFD_SOCKET_STATE SharedData;         // 共享 socket 状态
    PVOID ConnectCallInfo;               // TDI 连接调用信息
    PVOID ConnectReturnInfo;             // TDI 连接返回信息
    ...
} AFD_FCB, *PAFD_FCB;

socket 状态机(AFD 视角):

复制代码
SOCKET_STATE_CREATED → SOCKET_STATE_BOUND → SOCKET_STATE_CONNECTING → SOCKET_STATE_CONNECTED
                                        ↘ SOCKET_STATE_LISTENING
SOCKET_STATE_CLOSED (任何状态的终结)

5.4 挂起 IRP 管理

AFD 实现了标准的异步 IRP 管理模式:

复制代码
QueueUserModeIrp(FCB, Irp, Function)
   │
   ├─ 获取 socket 状态锁
   ├─ 将 IRP 挂入 FCB->PendingIrpList[Function] 链表
   └─ 返回 STATUS_PENDING

// 当 TDI 操作完成时:
UnlockAndMaybeComplete(FCB, Status, Irp, Count)
   ├─ 从 PendingIrpList 移除 IRP
   ├─ 填充 IoStatus
   └─ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT)

AfdCancelHandler 实现了 IRP 取消逻辑,支持取消挂起的 recv/send/connect/select 等操作。


6. TDI 传输驱动接口

6.1 TDI 定义

TDI (Transport Driver Interface) 定义在 tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h),是 Windows 传输驱动(TCP/IP、NetBEUI 等)的统一接口标准。

TDI 设备对象(由 tcpip.sys 创建):

设备 用途 打开方式
\Device\Tcp TCP 传输 CREATE + EA(地址或连接上下文)
\Device\Udp UDP 传输 CREATE + EA(地址文件)
\Device\Ip 原始 IP CREATE + EA
\Device\RawIp Raw IP CREATE + EA(协议号)

6.2 TDI 文件对象类型

TDI 定义了三种文件对象,通过 EA (Extended Attribute)ZwCreateFile/IRP_MJ_CREATE 时创建:

文件对象 EA 名称 用途
地址文件 TdiTransportAddress 绑定本地地址和端口
连接端点 TdiConnectionContext TCP 连接对象
控制通道 无 EA 管理/查询操作

6.3 TDI 操作(IRP Minor Function)

TDI 操作以内核 IRP 的 MinorFunction 形式发送:

c 复制代码
#define TDI_CONNECT                0x0A
#define TDI_LISTEN                 0x0B
#define TDI_ACCEPT                 0x0C
#define TDI_DISCONNECT             0x0D
#define TDI_SEND                   0x0E
#define TDI_RECEIVE                0x0F
#define TDI_SEND_DATAGRAM          0x10
#define TDI_RECEIVE_DATAGRAM       0x11
#define TDI_SET_EVENT_HANDLER      0x12
#define TDI_QUERY_INFORMATION      0x13
#define TDI_SET_INFORMATION        0x14
#define TDI_ASSOCIATE_ADDRESS      0x17
#define TDI_DISASSOCIATE_ADDRESS   0x18
#define TDI_ACTION                 0x19

6.4 tdihelpers 库

AFD 通过 tdihelpers 库(d:\reactos\drivers\network\tdihelpers\)构建 TDI 请求:

复制代码
TdiOpenAddressFile          → 通过 ZwCreateFile 打开地址文件 (带 TdiTransportAddress EA)
TdiOpenConnectionEndpointFile → 通过 ZwCreateFile 打开连接端点 (带 TdiConnectionContext EA)
TdiConnect                  → 构建 TDI_CONNECT 内部 IOCTL IRP 并 IoCallDriver
TdiSend / TdiReceive        → 构建 TDI_SEND / TDI_RECEIVE IRP
TdiAssociateAddressFile     → 关联地址文件和连接端点
TdiQueryInformation         → 查询传输信息 (MTU、最大数据报等)
TdiBuildConnectionInfo      → 构造 TDI_CONNECTION_INFORMATION

核心函数 TdiConnect(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L311-L380):

c 复制代码
NTSTATUS TdiConnect(PIRP *Irp, PFILE_OBJECT ConnectionObject, ...)
{
    DeviceObject = IoGetRelatedDeviceObject(ConnectionObject);
    // 构建 TDI_CONNECT 内部设备控制 IRP
    *Irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT,
                                            DeviceObject,
                                            ConnectionObject, ...);
    // 调用传输驱动
    return IoCallDriver(DeviceObject, *Irp);
}

IoCallDriver 链IoCallDriver 最终调用传输驱动的 MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL],即 tcpip.sys 的 TiDispatchInternal


7. DeviceIoControl 内核机制

7.1 用户态入口

复制代码
用户态: DeviceIoControl(hSocket, IOCTL_AFD_XXX, ...)
          │
          ▼
ntdll.dll: NtDeviceIoControlFile(hDevice, event, apc, apcCtx,
                                 &iosb, IoControlCode, ...)
          │
          ▼   (系统调用 → 内核)

7.2 内核 IRP 构造

内核的 IopXxxControlFile 构造 IRP_MJ_DEVICE_CONTROL IRP:

复制代码
IRP (IRP_MJ_DEVICE_CONTROL)
├── IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL
├── IrpSp->Parameters.DeviceIoControl:
│   ├── IoControlCode          ← IOCTL_AFD_XXX
│   ├── InputBufferLength
│   ├── OutputBufferLength
│   ├── Type3InputBuffer       ← 用户缓冲区 (METHOD_NEITHER)
│   └── (SystemBuffer 指向 MDL/系统缓冲)
├── Irp->AssociatedIrp.SystemBuffer
├── Irp->MdlAddress           ← 输出缓冲区 MDL
└── Irp->UserBuffer           ← 用户输出缓冲区

缓冲方法

  • METHOD_BUFFERED:系统缓冲 + MDL 映射,适合小数据量
  • METHOD_IN_DIRECT/METHOD_OUT_DIRECT:MDL 直连用户内存
  • METHOD_NEITHERType3InputBuffer 直接引用用户地址,AFD 使用此方式并自己锁定内存

7.3 内核 I/O 管理器调用链

复制代码
IopXxxControlFile (ntoskrnl)
   │
   ├─ IoBuildDeviceIoControlRequest 或复用 IopAllocateIrp
   ├─ 设置 IRP 栈位置 (IopAllocateIrp + IoSetNextIrpStackLocation)
   ├─ IoCallDriver(DeviceObject, Irp)
   │     └─ IopfCallDriver → 设备对象栈上的驱动分发
   │           └─ AFD: AfdDispatch(DeviceObject, Irp)   ← \Device\Afd
   │                 └─ IRP_MJ_DEVICE_CONTROL → switch(IOCTL_AFD_*)
   ├─ STATUS_PENDING → 返回给用户态,等待异步完成
   └─ 完成后: IoCompleteRequest → 唤醒等待的调用者

8. 典型操作调用链分析

8.1 socket() 创建

复制代码
socket(AF_INET, SOCK_STREAM, 0)
   │
   ▼
ws2_32: socket() → WsSockGetSocket → 调用 lpWSPSocket
   │
   ▼
AFD 提供者: CreateFile("\Device\Afd")           ← 内核句柄
   │
   ▼
内核: IRP_MJ_CREATE → AfdDispatch → AfdCreateSocket
   │
   ├─ 分配 AFD_FCB
   ├─ FileObject->FsContext = FCB
   ├─ 初始化 socket 状态机 (SOCKET_STATE_CREATED)
   └─ 返回句柄

8.2 bind() 绑定

复制代码
bind(sockfd, sockaddr, len)
   │
   ▼
ws2_32 → lpWSPBind
   │
   ▼
AFD 提供者: DeviceIoControl(handle, IOCTL_AFD_BIND, ...)
   │
   ▼
AFD: AfdBindSocket
   │
   ├─ 锁定用户 sockaddr 缓冲区
   ├─ TdiOpenAddressFile(&TdiDeviceName, Address)  ← ZwCreateFile \Device\Tcp
   │     └─ 构建带 TdiTransportAddress EA 的 CREATE IRP
   │     └─ tcpip.sys: TiCreateFileObject → FileOpenAddress
   ├─ 保存 TDI 地址文件句柄到 FCB->AddressFile
   └─ 状态 → SOCKET_STATE_BOUND

8.3 connect() 建立连接

复制代码
connect(sockfd, sockaddr, len)
   │
   ▼
ws2_32: connect() → Socket->Provider->Service.lpWSPConnect
   │        (sockctrl.c 中实现对 WSAEHOSTUNREACH 的重试/自动拨号)
   │
   ▼
AFD 提供者: DeviceIoControl(handle, IOCTL_AFD_CONNECT, ...)
   │
   ▼
AFD: AfdStreamSocketConnect
   │
   ├─ 解析远程地址 → TdiBuildConnectionInfo (FCB->ConnectCallInfo)
   ├─ 如果连接端点未打开:
   │    └─ TdiOpenConnectionEndpointFile(&TdiDeviceName)  ← ZwCreateFile \Device\Tcp (TdiConnectionContext EA)
   │    └─ TdiAssociateAddressFile(地址文件, 连接对象)
   ├─ QueueUserModeIrp(FCB, Irp, FUNCTION_CONNECT)  ← 挂起用户 IRP
   ├─ TdiConnect(&ConnectIrp, Connection.Object, ...)
   │    └─ TdiBuildInternalDeviceControlIrp(TDI_CONNECT) → IoCallDriver
   │         └─ tcpip.sys: TiDispatchInternal → DispTdiConnect → TCPConnect
   │              └─ 分配本地端口 → 发送 SYN → 等待 SYN+ACK
   ├─ (异步) TCP 连接完成 → TDI 完成例程 → AFD 完成回调
   │    └─ UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0)
   └─ IoCompleteRequest → 用户态 connect() 返回成功

8.4 send() 发送数据

复制代码
send(sockfd, buf, len, flags)
   │
   ▼
ws2_32 → lpWSPSend (send.c)
   │
   ▼
AFD 提供者: DeviceIoControl(handle, IOCTL_AFD_SEND, ...)
   │       (输入: AFD_SEND_INFO { BufferArray, BufferCount, ... })
   │
   ▼
AFD: AfdConnectedSocketWriteData
   │
   ├─ LockRequest: 锁定用户缓冲区 (MmProbeAndLockPages / AFD_MAPBUF)
   ├─ 构造 NDIS 数据包或直接使用 MDL
   ├─ 检查发送缓冲区空间 (FCB->Send.Window)
   ├─ 有空间 → TdiSend(&SendIrp, Connection.Object, ...)
   │     └─ TdiBuildInternalDeviceControlIrp(TDI_SEND) → IoCallDriver
   │          └─ tcpip.sys: DispTdiSend → TCPSendData
   │               └─ TCP 分段 → IP → 邻居 → LAN → NdisSend
   ├─ 无空间 → 挂起 IRP,等待 TCP 窗口更新
   ├─ 发送完成 → UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BytesSent)
   └─ IoCompleteRequest → 用户态 send() 返回

8.5 recv() 接收数据

复制代码
recv(sockfd, buf, len, flags)
   │
   ▼
ws2_32 → lpWSPRecv (recv.c)
   │
   ▼
AFD 提供者: DeviceIoControl(handle, IOCTL_AFD_RECV, ...)
   │
   ▼
AFD: AfdConnectedSocketReadData
   │
   ├─ 锁定接收缓冲区 (MDL)
   ├─ TdiReceive(&ReceiveIrp, Connection.Object, TDI_RECEIVE_NORMAL, ...)
   │     └─ TdiBuildInternalDeviceControlIrp(TDI_RECEIVE) → IoCallDriver
   │          └─ tcpip.sys: DispTdiReceive → TCPReceiveData
   │               └─ 数据到达时 HandleSignalledConnection → 拷贝到用户 MDL
   │               └─ DispDataRequestComplete → 完成 TDI IRP
   ├─ AFD 完成例程 → UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BytesRecv)
   └─ IoCompleteRequest → 用户态 recv() 返回

注意 :recv 还有事件驱动路径------若上层注册了 TDI_EVENT_RECEIVE 事件处理器(通过 TDI_SET_EVENT_HANDLER),则数据到达时直接调用事件回调而不是完成挂起的 IRP。

8.6 listen()/accept() 监听接受

复制代码
listen(sockfd, backlog)
   → IOCTL_AFD_START_LISTEN → AfdListenSocket
       → TdiAssociateAddressFile + 状态 → SOCKET_STATE_LISTENING

accept(sockfd, addr, len)
   → IOCTL_AFD_WAIT_FOR_LISTEN → AfdWaitForListen (等待新连接事件)
   → IOCTL_AFD_ACCEPT → AfdAccept
       → 为新连接分配新 AFD_FCB
       → TdiAccept / 从 TDI 事件队列取连接

8.7 select() 多路复用

复制代码
select(nfds, readfds, writefds, exceptfds, timeout)
   │
   ▼
ws2_32 → lpWSPSelect (select.c)
   │
   ▼
AFD 提供者: DeviceIoControl(handle, IOCTL_AFD_SELECT, ...)
   │       (输入: AFD_POLL_INFO { Handles[], ... })
   │
   ▼
AFD: AfdSelect
   │
   ├─ 为每个 socket 句柄创建 AFD_ACTIVE_POLL
   ├─ 将 Poll 加入 DeviceExt->Polls 全局链表
   ├─ 对每个 socket: TdiSetEventHandler / 查询可读可写状态
   ├─ 任一 socket 就绪 → 完成 IRP
   ├─ 超时 (AfdSelectTimeout) → 完成 IRP (无事件)
   └─ 返回事件掩码

9. 工作流程图

9.1 socket 生命周期总览

#mermaid-svg-6flFdndYIB0KcMWv{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-6flFdndYIB0KcMWv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6flFdndYIB0KcMWv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6flFdndYIB0KcMWv .error-icon{fill:#552222;}#mermaid-svg-6flFdndYIB0KcMWv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6flFdndYIB0KcMWv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6flFdndYIB0KcMWv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6flFdndYIB0KcMWv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6flFdndYIB0KcMWv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6flFdndYIB0KcMWv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6flFdndYIB0KcMWv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6flFdndYIB0KcMWv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6flFdndYIB0KcMWv .marker.cross{stroke:#333333;}#mermaid-svg-6flFdndYIB0KcMWv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6flFdndYIB0KcMWv p{margin:0;}#mermaid-svg-6flFdndYIB0KcMWv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6flFdndYIB0KcMWv .cluster-label text{fill:#333;}#mermaid-svg-6flFdndYIB0KcMWv .cluster-label span{color:#333;}#mermaid-svg-6flFdndYIB0KcMWv .cluster-label span p{background-color:transparent;}#mermaid-svg-6flFdndYIB0KcMWv .label text,#mermaid-svg-6flFdndYIB0KcMWv span{fill:#333;color:#333;}#mermaid-svg-6flFdndYIB0KcMWv .node rect,#mermaid-svg-6flFdndYIB0KcMWv .node circle,#mermaid-svg-6flFdndYIB0KcMWv .node ellipse,#mermaid-svg-6flFdndYIB0KcMWv .node polygon,#mermaid-svg-6flFdndYIB0KcMWv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6flFdndYIB0KcMWv .rough-node .label text,#mermaid-svg-6flFdndYIB0KcMWv .node .label text,#mermaid-svg-6flFdndYIB0KcMWv .image-shape .label,#mermaid-svg-6flFdndYIB0KcMWv .icon-shape .label{text-anchor:middle;}#mermaid-svg-6flFdndYIB0KcMWv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6flFdndYIB0KcMWv .rough-node .label,#mermaid-svg-6flFdndYIB0KcMWv .node .label,#mermaid-svg-6flFdndYIB0KcMWv .image-shape .label,#mermaid-svg-6flFdndYIB0KcMWv .icon-shape .label{text-align:center;}#mermaid-svg-6flFdndYIB0KcMWv .node.clickable{cursor:pointer;}#mermaid-svg-6flFdndYIB0KcMWv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6flFdndYIB0KcMWv .arrowheadPath{fill:#333333;}#mermaid-svg-6flFdndYIB0KcMWv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6flFdndYIB0KcMWv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6flFdndYIB0KcMWv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6flFdndYIB0KcMWv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6flFdndYIB0KcMWv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6flFdndYIB0KcMWv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6flFdndYIB0KcMWv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6flFdndYIB0KcMWv .cluster text{fill:#333;}#mermaid-svg-6flFdndYIB0KcMWv .cluster span{color:#333;}#mermaid-svg-6flFdndYIB0KcMWv 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-6flFdndYIB0KcMWv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6flFdndYIB0KcMWv rect.text{fill:none;stroke-width:0;}#mermaid-svg-6flFdndYIB0KcMWv .icon-shape,#mermaid-svg-6flFdndYIB0KcMWv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6flFdndYIB0KcMWv .icon-shape p,#mermaid-svg-6flFdndYIB0KcMWv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6flFdndYIB0KcMWv .icon-shape .label rect,#mermaid-svg-6flFdndYIB0KcMWv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6flFdndYIB0KcMWv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6flFdndYIB0KcMWv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6flFdndYIB0KcMWv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} IRP_MJ_CREATE

流式 TCP
数据报 UDP
流式-服务器
socket 创建
AfdCreateSocket
绑定地址?
bind → IOCTL_AFD_BIND
AfdBindSocket → TdiOpenAddressFile
连接型 or 数据报?
connect → IOCTL_AFD_CONNECT
直接 sendto/recvfrom
listen → IOCTL_AFD_START_LISTEN
accept → IOCTL_AFD_WAIT_FOR_LISTEN + IOCTL_AFD_ACCEPT
数据交换: send/recv
shutdown/closesocket → IOCTL_AFD_DISCONNECT
IRP_MJ_CLEANUP → AfdCleanupSocket
IRP_MJ_CLOSE → AfdCloseSocket → 释放 FCB

9.2 用户态 → AFD → TDI 调用链

#mermaid-svg-Rflsk4BzVq1I1be6{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-Rflsk4BzVq1I1be6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Rflsk4BzVq1I1be6 .error-icon{fill:#552222;}#mermaid-svg-Rflsk4BzVq1I1be6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Rflsk4BzVq1I1be6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Rflsk4BzVq1I1be6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Rflsk4BzVq1I1be6 .marker.cross{stroke:#333333;}#mermaid-svg-Rflsk4BzVq1I1be6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Rflsk4BzVq1I1be6 p{margin:0;}#mermaid-svg-Rflsk4BzVq1I1be6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 .cluster-label text{fill:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 .cluster-label span{color:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 .cluster-label span p{background-color:transparent;}#mermaid-svg-Rflsk4BzVq1I1be6 .label text,#mermaid-svg-Rflsk4BzVq1I1be6 span{fill:#333;color:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 .node rect,#mermaid-svg-Rflsk4BzVq1I1be6 .node circle,#mermaid-svg-Rflsk4BzVq1I1be6 .node ellipse,#mermaid-svg-Rflsk4BzVq1I1be6 .node polygon,#mermaid-svg-Rflsk4BzVq1I1be6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Rflsk4BzVq1I1be6 .rough-node .label text,#mermaid-svg-Rflsk4BzVq1I1be6 .node .label text,#mermaid-svg-Rflsk4BzVq1I1be6 .image-shape .label,#mermaid-svg-Rflsk4BzVq1I1be6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Rflsk4BzVq1I1be6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Rflsk4BzVq1I1be6 .rough-node .label,#mermaid-svg-Rflsk4BzVq1I1be6 .node .label,#mermaid-svg-Rflsk4BzVq1I1be6 .image-shape .label,#mermaid-svg-Rflsk4BzVq1I1be6 .icon-shape .label{text-align:center;}#mermaid-svg-Rflsk4BzVq1I1be6 .node.clickable{cursor:pointer;}#mermaid-svg-Rflsk4BzVq1I1be6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Rflsk4BzVq1I1be6 .arrowheadPath{fill:#333333;}#mermaid-svg-Rflsk4BzVq1I1be6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Rflsk4BzVq1I1be6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Rflsk4BzVq1I1be6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Rflsk4BzVq1I1be6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Rflsk4BzVq1I1be6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Rflsk4BzVq1I1be6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Rflsk4BzVq1I1be6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Rflsk4BzVq1I1be6 .cluster text{fill:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 .cluster span{color:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 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-Rflsk4BzVq1I1be6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Rflsk4BzVq1I1be6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Rflsk4BzVq1I1be6 .icon-shape,#mermaid-svg-Rflsk4BzVq1I1be6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Rflsk4BzVq1I1be6 .icon-shape p,#mermaid-svg-Rflsk4BzVq1I1be6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Rflsk4BzVq1I1be6 .icon-shape .label rect,#mermaid-svg-Rflsk4BzVq1I1be6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Rflsk4BzVq1I1be6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Rflsk4BzVq1I1be6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Rflsk4BzVq1I1be6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} tcpip.sys
TDI 层
内核态 AFD.sys
用户态

没有
应用程序: send 数据
ws2_32.dll: send 函数
查找 WSSOCKET → 调用 lpWSPSend
AFD 提供者: 组织 AFD_SEND_INFO
DeviceIoControl\\hSocket, IOCTL_AFD_SEND
NtDeviceIoControlFile
I/O 管理器构造 IRP_MJ_DEVICE_CONTROL
AfdDispatch 分发
AfdConnectedSocketWriteData
LockRequest 锁定用户缓冲区
发送窗口有空间?
TdiSend 调用
挂起 IRP 到 PendingIrpList
TdiBuildInternalDeviceControlIrp TDI_SEND
IoCallDriver 传输驱动
TiDispatchInternal
DispTdiSend
TCPSendData
IP 层发送

9.3 异步完成流程

tcpip.sys tdihelpers AFD.sys AFD 提供者 应用程序 tcpip.sys tdihelpers AFD.sys AFD 提供者 应用程序 #mermaid-svg-PNKibQMHbnjDiJUx{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-PNKibQMHbnjDiJUx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PNKibQMHbnjDiJUx .error-icon{fill:#552222;}#mermaid-svg-PNKibQMHbnjDiJUx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PNKibQMHbnjDiJUx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PNKibQMHbnjDiJUx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PNKibQMHbnjDiJUx .marker.cross{stroke:#333333;}#mermaid-svg-PNKibQMHbnjDiJUx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PNKibQMHbnjDiJUx p{margin:0;}#mermaid-svg-PNKibQMHbnjDiJUx .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PNKibQMHbnjDiJUx text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-PNKibQMHbnjDiJUx .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-PNKibQMHbnjDiJUx .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-PNKibQMHbnjDiJUx .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-PNKibQMHbnjDiJUx .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-PNKibQMHbnjDiJUx #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-PNKibQMHbnjDiJUx .sequenceNumber{fill:white;}#mermaid-svg-PNKibQMHbnjDiJUx #sequencenumber{fill:#333;}#mermaid-svg-PNKibQMHbnjDiJUx #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-PNKibQMHbnjDiJUx .messageText{fill:#333;stroke:none;}#mermaid-svg-PNKibQMHbnjDiJUx .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PNKibQMHbnjDiJUx .labelText,#mermaid-svg-PNKibQMHbnjDiJUx .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-PNKibQMHbnjDiJUx .loopText,#mermaid-svg-PNKibQMHbnjDiJUx .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-PNKibQMHbnjDiJUx .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-PNKibQMHbnjDiJUx .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-PNKibQMHbnjDiJUx .noteText,#mermaid-svg-PNKibQMHbnjDiJUx .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-PNKibQMHbnjDiJUx .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PNKibQMHbnjDiJUx .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PNKibQMHbnjDiJUx .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PNKibQMHbnjDiJUx .actorPopupMenu{position:absolute;}#mermaid-svg-PNKibQMHbnjDiJUx .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-PNKibQMHbnjDiJUx .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PNKibQMHbnjDiJUx .actor-man circle,#mermaid-svg-PNKibQMHbnjDiJUx line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-PNKibQMHbnjDiJUx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据到达/窗口更新... send(buf) DeviceIoControl(IOCTL_AFD_SEND) AfdConnectedSocketWriteData LockRequest (锁定用户内存) TdiSend TDI_SEND IRP (IoCallDriver) TCPSendData 处理 TCP 窗口不足 → 挂起 TDI IRP STATUS_PENDING 发送完成 → 完成 TDI IRP TDI IRP 完成 (IoCompleteRequest) 完成例程 → UnlockAndMaybeComplete 用户 IRP 完成 send() 返回成功


10. 数据流图

10.1 send 数据流(带数据)

复制代码
用户态                                        内核态
┌────────────┐   ┌────────────┐   ┌────────────────────────────┐
│  App.buf   │──▶│  WSABUF[]  │──▶│  AFD_SEND_INFO              │
│  (用户内存) │   │ (用户内存)  │   │  ├─ BufferArray[0].Buffer ──┼──▶ 用户地址
└────────────┘   └────────────┘   │  ├─ BufferArray[0].Length   │
                                  │  ├─ BufferCount             │
                                  │  └─ Flags                   │
                                  └────────────┬───────────────┘
                                               │ LockRequest
                                               │ MmProbeAndLockPages
                                               ▼
                                  ┌────────────────────────────┐
                                  │ AFD_MAPBUF[] (MDL 数组)     │
                                  │  ├─ BufferAddress (用户VA)  │
                                  │  └─ Mdl (锁定页)            │
                                  └────────────┬───────────────┘
                                               │ TdiSend (MDL → NDIS 包)
                                               ▼
                                  ┌────────────────────────────┐
                                  │ TDI_SEND IRP               │
                                  │  ├─ Parameters.SendLength  │
                                  │  └─ MdlAddress (数据MDL)   │
                                  └────────────┬───────────────┘
                                               │ IoCallDriver
                                               ▼
                                  ┌────────────────────────────┐
                                  │ tcpip.sys: TCPSendData     │
                                  │  └─ sk_buff 拷贝/引用       │
                                  │  └─ TCP 分段+校验和         │
                                  │  └─ IP → 邻居 → LAN        │
                                  └────────────┬───────────────┘
                                               │ NdisSend
                                               ▼
                                              网卡

10.2 recv 数据流(带数据)

复制代码
网卡                                            
  │  数据帧
  ▼
ndis.sys → 微型端口接收
  │
  ▼
tcpip.sys: LanReceiveWorker → IPReceive → TCPReceive
  │
  ├─ 数据入 TCP 接收队列
  ├─ HandleSignalledConnection
  ├─ 查找挂起的 TDI_RECEIVE IRP (FCB->ReceiveIrp)
  │    └─ 拷贝数据到 IRP->MdlAddress 指向的用户缓冲区
  ├─ 完成 TDI IRP (IoCompleteRequest)
  │
  ▼
AFD.sys: TDI 完成例程
  │
  ├─ UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BytesReceived)
  │    ├─ IoStatus.Information = 实际接收字节数
  │    └─ IoCompleteRequest (用户 IRP)
  │
  ▼
用户态: DeviceIoControl 返回
  │
  ▼
AFD 提供者: 从输出缓冲区读取字节数
  │
  ▼
ws2_32: lpWSPRecv 返回
  │
  ▼
应用程序: recv() 返回数据长度

11. 关键函数索引

11.1 用户态 (ws2_32.dll)

函数 位置 说明
connect sockctrl.c(file:///d:/reactos/dll/win32/ws2_32/src/sockctrl.c#L21-L116) Winsock connect,调用 lpWSPConnect
socket socklife.c(file:///d:/reactos/dll/win32/ws2_32/src/socklife.c) 创建 socket,调用 lpWSPSocket
WsSockGetSocket dsocket.c(file:///d:/reactos/dll/win32/ws2_32/src/dsocket.c) 根据 SOCKET 句柄查找 WSSOCKET 上下文
LoadTransportProviders dprovide.c(file:///d:/reactos/dll/win32/ws2_32/src/dprovide.c) 加载 WSP 服务提供者 (WSPStartup)
WSAStartup startup.c(file:///d:/reactos/dll/win32/ws2_32/src/startup.c) Winsock 初始化

11.2 内核态 AFD (AFD.sys)

函数 位置 说明
DriverEntry main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L1318-L1359) 创建 \Device\Afd,注册统一分发
AfdDispatch main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L906-L1094) 统一 IRP 分发,switch IOCTL_AFD_*
AfdCreateSocket main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L302) 创建 AFD_FCB
AfdCleanupSocket main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L426) 清理挂起 IRP
AfdCloseSocket main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L460) 关闭 socket,释放 FCB
AfdStreamSocketConnect connect.c(file:///d:/reactos/drivers/network/afd/afd/connect.c#L518) 处理 IOCTL_AFD_CONNECT,调用 TdiConnect
AfdConnectedSocketWriteData write.c(file:///d:/reactos/drivers/network/afd/afd/write.c) 处理 IOCTL_AFD_SEND,调用 TdiSend
AfdConnectedSocketReadData read.c(file:///d:/reactos/drivers/network/afd/afd/read.c) 处理 IOCTL_AFD_RECV,调用 TdiReceive
AfdListenSocket listen.c(file:///d:/reactos/drivers/network/afd/afd/listen.c) 处理 IOCTL_AFD_START_LISTEN
AfdSelect select.c(file:///d:/reactos/drivers/network/afd/afd/select.c) 处理 IOCTL_AFD_SELECT
AfdEventSelect event.c(file:///d:/reactos/drivers/network/afd/afd/event.c) 处理 IOCTL_AFD_EVENT_SELECT
AfdCancelHandler main.c(file:///d:/reactos/drivers/network/afd/afd/main.c#L1186) IRP 取消处理
QueueUserModeIrp main.c(file:///d:/reactos/drivers/network/afd/afd/main.c) 挂起用户态 IRP 到 FCB 队列

11.3 TDI 辅助 (tdihelpers)

函数 位置 说明
TdiOpenDevice tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L68-L146) ZwCreateFile 打开 TDI 设备
TdiOpenAddressFile tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L148-L201) 打开地址文件 (EA: TdiTransportAddress)
TdiOpenConnectionEndpointFile tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L258-L308) 打开连接端点 (EA: TdiConnectionContext)
TdiConnect tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L311-L380) 构建 TDI_CONNECT IRP 并调用传输驱动
TdiQueryMaxDatagramLength tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L203-L256) 查询最大数据报长度
TdiBuildConnectionInfo tdiconn.c(file:///d:/reactos/drivers/network/tdihelpers/tdiconn.c#L246-L254) 构造 TDI_CONNECTION_INFORMATION

11.4 TDI 头文件

头文件 路径 说明
tdikrnl.h sdk/include/ddk/tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h) TDI 内核接口定义 (TDI_* Minor Function)
tdi.h sdk/include/ddk/tdi.h(file:///d:/reactos/sdk/include/ddk/tdi.h) TDI 数据结构 (TA_IP_ADDRESS 等)
tdiinfo.h sdk/include/ddk/tdiinfo.h(file:///d:/reactos/sdk/include/ddk/tdiinfo.h) TDI 信息查询定义

附录 A:IOCTL 代码结构

Windows IOCTL 代码的组成:

复制代码
IoControlCode = CTL_CODE(DeviceType, Function, Method, Access)
                 │            │          │         │
                 │            │          │         └── FILE_ANY_ACCESS / FILE_READ/WRITE_DATA
                 │            │          └──────────── METHOD_BUFFERED/IN_DIRECT/OUT_DIRECT/NEITHER
                 │            └─────────────────────── 功能序号
                 └──────────────────────────────────── 设备类型 (FILE_DEVICE_XXX)

示例: IOCTL_AFD_CONNECT = CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x41, METHOD_NEITHER, FILE_ANY_ACCESS)

附录 B:AFD 与 tcpip.sys 设备对象对照

组件 设备对象 主要 MajorFunction 发起者
AFD.sys \Device\Afd IRP_MJ_DEVICE_CONTROL (IOCTL_AFD_*) 用户态 WSP
tcpip.sys \Device\Tcp IRP_MJ_INTERNAL_DEVICE_CONTROL (TDI_*) AFD (tdihelpers)
tcpip.sys \Device\Udp 同上 AFD (tdihelpers)
tcpip.sys \Device\Ip / \Device\RawIp 同上 其他 TDI 客户端

附录 C:相关文档

  • TCPIP 驱动分析(file:///d:/reactos/doc/TCPIP_驱动分析.md) --- tcpip.sys 协议栈内部实现
  • NDIS 驱动分析(file:///d:/reactos/doc/NDIS_驱动分析.md) --- ndis.sys 中间层实现
相关推荐
小洁忘了怎么分身17 小时前
多样本空间转录组 Harmony 整合与标签转移指南
网络·r语言·生信分析
郑午时光18 小时前
全球首发!2026年适合IP短剧长视频的AI视频生成工具,即梦seedance2.5轻松做短剧
人工智能·tcp/ip·音视频
发光小北19 小时前
PLC 私有协议采集网关如何应用?
网络协议
三言老师20 小时前
CentOS8 Firewalld 高级规则中级实操教程
linux·运维·服务器·网络·centos
rcms1527026921821 小时前
TEL 3308-000065-13 印刷电路板
网络
xywww16821 小时前
Claude Opus 5 企业使用怎么选:场景分层、成本测算和接入风险清单
网络
望安认证1 天前
CRA 与 CE、RED、EUCC、NIS2、GDPR、AI Act、Data Act、DORA 等欧盟法规的关系:从法案结构看数字产品出海合规
网络·欧盟·cra·网络弹性法案·cra认证
Hrain-AI1 天前
2026企业AI Agent本地化落地:6平台横评+搭建步骤+成本模板
服务器·网络·人工智能
便利店10241 天前
企业远程办公如何打通内网?网络层隧道与封装直觉
运维·服务器·网络·vpn·隧道
00后程序员张1 天前
抓包鹰 电脑本机网络连接表怎么看?哪些程序在联网 进程归属与可疑 IP 追溯
网络协议·计算机网络·网络安全·ios·adb·https·udp