TDI (传输驱动接口 Transport Driver Interface) 详细分析
目录
- 概述
- 整体架构
- [TDI 文件对象模型](#TDI 文件对象模型)
- [TDI 数据结构](#TDI 数据结构)
- [TDI 操作 (Request Codes)](#TDI 操作 (Request Codes))
- [TDI 事件模型](#TDI 事件模型)
- [TDI IRP 构建机制 (TdiBuild*)](#TDI IRP 构建机制 (TdiBuild*))
- [tdihelpers 库](#tdihelpers 库)
- [TDI 信息查询](#TDI 信息查询)
- 工作流程图
- 数据流图
- 关键定义索引
1. 概述
TDI (Transport Driver Interface,传输驱动接口) 是 Windows 定义的内核态网络接口标准,位于内核的网络客户端(如 AFD.sys、NetBIOS)与传输驱动(如 tcpip.sys)之间。它定义了传输层驱动必须实现的统一接口,使上层的网络客户端无需关心底层使用的是 TCP/IP、IPX 还是其他协议。
ReactOS 的 TDI 定义位于 d:\reactos\sdk\include\ddk\tdikrnl.h(内核模式)和 d:\reactos\sdk\include\psdk\tdi.h(用户模式)。
1.1 架构定位
┌─────────────────────────────────────────────┐
│ 内核态网络客户端 (TDI Clients) │
│ ├─ AFD.sys (Winsock 内核实现) │
│ ├─ NetBIOS 驱动 │
│ └─ 其他 TDI 客户端 │
└──────────────────┬──────────────────────────┘
│ TDI 调用 (IRP_MJ_INTERNAL_DEVICE_CONTROL)
│ TdiBuild* 宏构建 IRP → IoCallDriver
┌──────────────────▼──────────────────────────┐
│ TDI 层 ← ★ 本文分析对象 │
│ │
│ 文件对象 (File Object) │
│ ├─ 地址文件 (TransportAddress) │
│ ├─ 连接端点 (ConnectionContext) │
│ └─ 控制通道 (ControlChannel) │
│ │
│ 操作 (MinorFunction) │
│ ├─ TDI_CONNECT / TDI_LISTEN / TDI_ACCEPT │
│ ├─ TDI_SEND / TDI_RECEIVE │
│ ├─ TDI_SEND_DATAGRAM / TDI_RECEIVE_DATAGRAM
│ ├─ TDI_SET_EVENT_HANDLER │
│ └─ TDI_QUERY/SET_INFORMATION │
│ │
│ 事件回调 (Event Handlers) │
│ ├─ TDI_EVENT_CONNECT / DISCONNECT │
│ ├─ TDI_EVENT_RECEIVE / RECEIVE_DATAGRAM │
│ └─ TDI_EVENT_ERROR / SEND_POSSIBLE │
└──────────────────┬──────────────────────────┘
│ TDI 操作由传输驱动处理
┌──────────────────▼──────────────────────────┐
│ 传输驱动 (TDI Providers) │
│ └─ tcpip.sys (TCP/UDP/IP) │
└──────────────────┬──────────────────────────┘
│ NDIS
▼
ndis.sys → 网卡驱动
1.2 TDI 的本质
TDI 不是 一个独立的模块或 DLL,而是一组接口规范,通过以下方式实现:
- 头文件定义 :
tdikrnl.h定义请求结构、宏和事件回调原型 - 文件对象语义 :传输驱动通过
\Device\Tcp等设备对象暴露,客户端用ZwCreateFile打开 - IRP 分发 :TDI 操作通过
IRP_MJ_INTERNAL_DEVICE_CONTROL的MinorFunction字段区分 - 事件回调:客户端注册事件处理器,传输驱动在数据到达时回调
1.3 与 NDIS 的区别
| 维度 | TDI | NDIS |
|---|---|---|
| 位置 | 传输层与网络客户端之间 | 协议栈与网卡驱动之间 |
| 使用者 | AFD.sys、NetBIOS 等 | tcpip.sys 自身 |
| 数据单元 | TSDU (传输服务数据单元) | 帧/包 |
| 对象 | 文件对象 (地址/连接/控制) | 适配器/协议绑定 |
| IRP 类型 | IRP_MJ_INTERNAL_DEVICE_CONTROL |
无直接 IRP 接口 |
| 事件 | TDI_EVENT_* 回调 | NDIS Status 回调 |
2. 整体架构
2.1 TDI 客户端与服务提供者
TDI 客户端 (Client) TDI 提供者 (Provider)
┌──────────────┐ ┌──────────────┐
│ AFD.sys │─── TDI 请求 ────────▶│ tcpip.sys │
│ │ │ │
│ 1. 打开文件 │── ZwCreateFile ─────▶│ \Device\Tcp │
│ 2. 设置事件 │── TDI_SET_EVENT_HANDLER ─▶│ 注册回调 │
│ 3. 发起操作 │── TDI_CONNECT 等 ───▶│ 处理请求 │
│ 4. 接收通知 │◀── 事件回调 ─────────│ 数据到达 │
└──────────────┘ └──────────────┘
2.2 头文件层次
| 头文件 | 位置 | 内容 |
|---|---|---|
tdikrnl.h |
sdk/include/ddk/tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h) | 内核模式 TDI 定义(请求结构、TdiBuild 宏、事件原型) |
tdi.h |
sdk/include/psdk/tdi.h(file:///d:/reactos/sdk/include/psdk/tdi.h) | 用户模式 TDI 定义(TDI_REQUEST、连接信息、地址结构) |
tdistat.h |
sdk/include/ddk/tdistat.h(file:///d:/reactos/sdk/include/ddk/tdistat.h) | TDI 状态码 |
tdiinfo.h |
sdk/include/psdk/tdiinfo.h(file:///d:/reactos/sdk/include/psdk/tdiinfo.h) | TDI 信息类定义 |
ntddtdi.h |
sdk/include/psdk/ntddtdi.h(file:///d:/reactos/sdk/include/psdk/ntddtdi.h) | TDI IOCTL 定义 |
2.3 tdihelpers 库
ReactOS 提供了一个 tdihelpers 辅助库(d:\reactos\drivers\network\tdihelpers\),封装了 TDI 的常用操作,被 AFD.sys 和 NETIO 使用:
tdihelpers/
├── tdi.c # TdiOpenDevice/TdiOpenAddressFile/TdiOpenConnectionEndpointFile
│ # TdiAssociateAddressFile/TdiDisassociateAddressFile
│ # TdiListen/TdiAccept/TdiSetEventHandler/TdiQueryDeviceControl
├── tdiconn.c # TdiConnect/TdiBuildConnectionInfo 等连接辅助
└── include/
├── tdi.h # tdihelpers 头文件
└── tdiconn.h # 连接辅助声明
3. TDI 文件对象模型
TDI 定义了三种文件对象,通过 ZwCreateFile 在传输设备的命名空间下创建。
3.1 文件对象类型
| 类型 | FsContext2 值 | 创建方式 (EA) | 用途 |
|---|---|---|---|
| 地址文件 | TDI_TRANSPORT_ADDRESS_FILE (1) |
CREATE + TransportAddress EA |
绑定本地地址,用于无连接通信 |
| 连接端点 | TDI_CONNECTION_FILE (2) |
CREATE + ConnectionContext EA |
面向连接通信(TCP) |
| 控制通道 | TDI_CONTROL_CHANNEL_FILE (3) |
CREATE(无 EA) | 管理/信息查询 |
c
#define TdiTransportAddress "TransportAddress"
#define TdiConnectionContext "ConnectionContext"
#define TDI_TRANSPORT_ADDRESS_LENGTH (sizeof(TdiTransportAddress) - 1)
#define TDI_CONNECTION_CONTEXT_LENGTH (sizeof(TdiConnectionContext) - 1)
3.2 地址文件创建 (带 EA)
客户端通过 FILE_FULL_EA_INFORMATION 传递 EA 参数:
ZwCreateFile(..., EaBuffer)
│
▼
EaBuffer:
┌─────────────────────────────────────────────┐
│ FILE_FULL_EA_INFORMATION │
│ EaNameLength = 17 ("TransportAddress") │
│ EaName = "TransportAddress" │
│ EaValueLength = sizeof(TA_IP_ADDRESS) │
├─────────────────────────────────────────────┤
│ TA_IP_ADDRESS (EA 值) │
│ TAAddressCount = 1 │
│ Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP
│ Address[0].AddressType = TDI_ADDRESS_TYPE_IP
│ Address[0].Address[0] = { sin_port, in_addr, sin_zero }
└─────────────────────────────────────────────┘
3.3 连接端点创建 (带 EA)
ZwCreateFile(..., EaBuffer)
│
▼
EaBuffer:
┌─────────────────────────────────────────────┐
│ FILE_FULL_EA_INFORMATION │
│ EaNameLength = 16 ("ConnectionContext") │
│ EaName = "ConnectionContext" │
│ EaValueLength = sizeof(PVOID) │
├─────────────────────────────────────────────┤
│ PVOID ContextArea (连接上下文指针) │
└─────────────────────────────────────────────┘
3.4 文件对象的关系
┌──────────────────────┐
│ 传输设备对象 │
│ \Device\Tcp │
└──────────┬───────────┘
│
┌─────────────┼─────────────┐
│ │ │
┌──────▼─────┐ ┌─────▼──────┐ ┌────▼────────┐
│ 地址文件 │ │ 连接端点 │ │ 控制通道 │
│ (AddressFile)│ │ (Connection)│ │ (Control) │
└──────┬─────┘ └─────┬──────┘ └─────────────┘
│ │
│ TDI_ASSOCIATE_ADDRESS
│ (通过 AddressHandle 关联)
└────────────►
关联操作 :连接端点创建后,必须通过 TDI_ASSOCIATE_ADDRESS 操作关联一个地址文件,才能发起连接。
4. TDI 数据结构
4.1 TDI_CONNECTION_INFORMATION --- 连接信息
定义在 tdi.h(file:///d:/reactos/sdk/include/psdk/tdi.h#L39-L46):
c
typedef struct _TDI_CONNECTION_INFORMATION {
LONG UserDataLength; // 用户数据长度 (连接时传递)
PVOID UserData; // 用户数据指针
LONG OptionsLength; // 选项长度
PVOID Options; // 选项指针
LONG RemoteAddressLength; // 远端地址长度
PVOID RemoteAddress; // 远端地址 (TRANSPORT_ADDRESS)
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;
用于 TDI_CONNECT、TDI_LISTEN、TDI_ACCEPT、TDI_SEND_DATAGRAM 等操作。
4.2 TRANSPORT_ADDRESS --- 传输地址
c
typedef struct _TRANSPORT_ADDRESS {
LONG TAAddressCount; // 地址个数
TA_ADDRESS Address[1]; // 地址数组
} TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;
typedef struct _TA_ADDRESS {
USHORT AddressLength; // 地址长度
USHORT AddressType; // 地址类型 (TDI_ADDRESS_TYPE_*)
UCHAR Address[1]; // 地址数据
} TA_ADDRESS, *PTA_ADDRESS;
4.3 TDI_ADDRESS_IP --- IPv4 地址
c
typedef struct _TDI_ADDRESS_IP {
USHORT sin_port; // 端口 (网络字节序)
ULONG in_addr; // IP 地址 (网络字节序)
UCHAR sin_zero[8]; // 填充
} TDI_ADDRESS_IP, *PTDI_ADDRESS_IP;
IPv4 地址组合(TA_IP_ADDRESS):
c
typedef struct _TA_IP_ADDRESS {
LONG TAAddressCount; // = 1
struct {
USHORT AddressLength; // = sizeof(TDI_ADDRESS_IP) = 14
USHORT AddressType; // = TDI_ADDRESS_TYPE_IP = 2
TDI_ADDRESS_IP Address[1]; // 实际 IP 地址
} Address[1];
} TA_IP_ADDRESS, *PTA_IP_ADDRESS;
4.4 地址类型常量
c
#define TDI_ADDRESS_TYPE_UNSPEC 0 // 未指定
#define TDI_ADDRESS_TYPE_IP 2 // IPv4
#define TDI_ADDRESS_TYPE_IPX 6 // IPX
#define TDI_ADDRESS_TYPE_NETBIOS 17 // NetBIOS
#define TDI_ADDRESS_TYPE_IP6 23 // IPv6
#define TDI_ADDRESS_TYPE_NETBIOS_EX 22 // NetBIOS 扩展
4.5 TDI_REQUEST --- 请求基结构 (用户模式)
c
typedef struct _TDI_REQUEST {
union {
HANDLE AddressHandle; // 地址文件句柄
CONNECTION_CONTEXT ConnectionContext; // 连接上下文
HANDLE ControlChannel; // 控制通道
} Handle;
PVOID RequestNotifyObject; // 完成通知对象
PVOID RequestContext; // 请求上下文
TDI_STATUS TdiStatus; // 状态
} TDI_REQUEST, *PTDI_REQUEST;
4.6 TDI_REQUEST_KERNEL --- 内核请求基结构
定义在 tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h#L39-L44):
c
typedef struct _TDI_REQUEST_KERNEL {
ULONG RequestFlags; // 请求标志
PTDI_CONNECTION_INFORMATION RequestConnectionInformation; // 请求连接信息
PTDI_CONNECTION_INFORMATION ReturnConnectionInformation; // 返回连接信息
PVOID RequestSpecific; // 请求特定参数 (如超时)
} TDI_REQUEST_KERNEL, *PTDI_REQUEST_KERNEL;
4.7 各类请求的参数结构
| 请求 | 结构 | 附加参数 |
|---|---|---|
TDI_ASSOCIATE_ADDRESS |
TDI_REQUEST_KERNEL_ASSOCIATE |
AddressHandle |
TDI_CONNECT |
TDI_REQUEST_KERNEL |
RequestSpecific = 超时指针 |
TDI_LISTEN |
TDI_REQUEST_KERNEL |
RequestFlags |
TDI_ACCEPT |
TDI_REQUEST_KERNEL_ACCEPT |
Request/Return ConnectionInfo |
TDI_DISCONNECT |
TDI_REQUEST_KERNEL |
RequestFlags + RequestSpecific(超时) |
TDI_SEND |
TDI_REQUEST_KERNEL_SEND |
SendLength + SendFlags |
TDI_RECEIVE |
TDI_REQUEST_KERNEL_RECEIVE |
ReceiveLength + ReceiveFlags |
TDI_SEND_DATAGRAM |
TDI_REQUEST_KERNEL_SENDDG |
SendLength + SendDatagramInformation |
TDI_RECEIVE_DATAGRAM |
TDI_REQUEST_KERNEL_RECEIVEDG |
ReceiveLength + DatagramInfo + Flags |
TDI_SET_EVENT_HANDLER |
TDI_REQUEST_KERNEL_SET_EVENT |
EventType + EventHandler + EventContext |
TDI_QUERY_INFORMATION |
TDI_REQUEST_KERNEL_QUERY_INFORMATION |
QueryType |
TDI_SET_INFORMATION |
TDI_REQUEST_KERNEL_SET_INFORMATION |
SetType |
5. TDI 操作 (Request Codes)
5.1 操作码定义
定义在 tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h#L47-L63):
c
/* Request codes */
#define TDI_ASSOCIATE_ADDRESS 0x01 // 关联地址文件
#define TDI_DISASSOCIATE_ADDRESS 0x02 // 解除地址关联
#define TDI_CONNECT 0x03 // 连接
#define TDI_LISTEN 0x04 // 监听
#define TDI_ACCEPT 0x05 // 接受
#define TDI_DISCONNECT 0x06 // 断开
#define TDI_SEND 0x07 // 发送
#define TDI_RECEIVE 0x08 // 接收
#define TDI_SEND_DATAGRAM 0x09 // 发送数据报
#define TDI_RECEIVE_DATAGRAM 0x0A // 接收数据报
#define TDI_SET_EVENT_HANDLER 0x0B // 设置事件处理器
#define TDI_QUERY_INFORMATION 0x0C // 查询信息
#define TDI_SET_INFORMATION 0x0D // 设置信息
#define TDI_ACTION 0x0E // 动作
/* Direct-call operations */
#define TDI_DIRECT_SEND 0x27 // 直接发送 (快速路径)
#define TDI_DIRECT_SEND_DATAGRAM 0x29 // 直接发送数据报
5.2 IRP 结构
TDI 操作以 IRP_MJ_INTERNAL_DEVICE_CONTROL IRP 发送,MinorFunction 字段存放操作码:
IRP
├── MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL
├── MinorFunction = TDI_CONNECT (0x03) 等
├── Parameters (union)
│ ├── TDI_REQUEST_KERNEL (通过 _IrpSp->Parameters 访问)
│ │ ├── RequestFlags
│ │ ├── RequestConnectionInformation
│ │ ├── ReturnConnectionInformation
│ │ └── RequestSpecific
│ └── 各请求特有参数
├── MdlAddress (数据缓冲, 用于 SEND/RECEIVE)
├── FileObject (目标文件对象: 连接端点/地址文件)
└── DeviceObject (传输设备对象)
5.3 各操作语义
TDI_CONNECT (0x03)
客户端 → 传输驱动:
RequestConnectionInformation->RemoteAddress = 远端地址 (TRANSPORT_ADDRESS)
RequestSpecific = 超时 (LARGE_INTEGER*)
传输驱动 → 客户端:
成功: ReturnConnectionInformation->RemoteAddress 填实际连接地址
状态: STATUS_SUCCESS / STATUS_PENDING (异步)
TDI_LISTEN (0x04)
客户端 → 传输驱动:
RequestFlags = TDI_QUERY_ACCEPT (表示查询可接受的连接)
RequestConnectionInformation = 监听限制信息
传输驱动 → 客户端:
新连接到达时: 通过 TDI_EVENT_CONNECT 事件通知
完成: ReturnConnectionInformation 包含连接信息
TDI_SEND (0x07)
客户端 → 传输驱动:
SendLength = 发送字节数
SendFlags = TDI_SEND_EXPEDITED / TDI_SEND_PARTIAL / TDI_SEND_NON_BLOCKING
Irp->MdlAddress = 数据缓冲 (MDL 链)
传输驱动 → 客户端:
IOSB.Information = 实际发送字节数
发送标志:
c
#define TDI_SEND_EXPEDITED 0x0020 // 紧急数据 (MSG_OOB)
#define TDI_SEND_PARTIAL 0x0040 // 部分发送
#define TDI_SEND_NO_RESPONSE_EXPECTED 0x0080 // 无需响应
#define TDI_SEND_NON_BLOCKING 0x0100 // 非阻塞
#define TDI_SEND_AND_DISCONNECT 0x0200 // 发送后断开
TDI_RECEIVE (0x08)
客户端 → 传输驱动:
ReceiveLength = 接收缓冲长度
ReceiveFlags = TDI_RECEIVE_NORMAL / PEEK / EXPEDITED 等
Irp->MdlAddress = 接收缓冲 (MDL)
传输驱动 → 客户端:
IOSB.Information = 实际接收字节数
接收标志:
c
#define TDI_RECEIVE_BROADCAST 0x00000004 // 广播
#define TDI_RECEIVE_MULTICAST 0x00000008 // 多播
#define TDI_RECEIVE_PARTIAL 0x00000010 // 部分接收
#define TDI_RECEIVE_NORMAL 0x00000020 // 正常
#define TDI_RECEIVE_EXPEDITED 0x00000040 // 紧急
#define TDI_RECEIVE_PEEK 0x00000080 // 偷看 (不移除)
#define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 // 复制前瞻数据
#define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 // 完整消息
TDI_DISCONNECT (0x06)
c
#define TDI_DISCONNECT_WAIT 0x0001 // 等待完成
#define TDI_DISCONNECT_ABORT 0x0002 // 立即中止 (RST)
#define TDI_DISCONNECT_RELEASE 0x0004 // 释放
TDI_SET_EVENT_HANDLER (0x0B)
客户端 → 传输驱动:
EventType = TDI_EVENT_* 事件类型
EventHandler = 回调函数指针
EventContext = 回调上下文 (通常是客户端对象指针)
传输驱动:
保存回调, 事件发生时调用 EventHandler(EventContext, ...)
传 NULL Handler 表示注销事件处理器
6. TDI 事件模型
6.1 事件类型
定义在 tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h#L146-L156):
c
#define TDI_EVENT_CONNECT 0 // 连接请求到达 (监听 socket)
#define TDI_EVENT_DISCONNECT 1 // 连接断开
#define TDI_EVENT_ERROR 2 // 错误
#define TDI_EVENT_RECEIVE 3 // 数据到达
#define TDI_EVENT_RECEIVE_DATAGRAM 4 // 数据报到达
#define TDI_EVENT_RECEIVE_EXPEDITED 5 // 紧急数据到达
#define TDI_EVENT_SEND_POSSIBLE 6 // 可以发送
#define TDI_EVENT_CHAINED_RECEIVE 7 // 链式接收 (MDL 直接)
#define TDI_EVENT_CHAINED_RECEIVE_DATAGRAM 8 // 链式数据报接收
#define TDI_EVENT_CHAINED_RECEIVE_EXPEDITED 9 // 链式紧急接收
#define TDI_EVENT_ERROR_EX 10 // 扩展错误
6.2 事件回调原型
PTDI_IND_RECEIVE --- 数据到达
c
typedef NTSTATUS (NTAPI *PTDI_IND_RECEIVE)(
_In_opt_ PVOID TdiEventContext, // 注册时的上下文 (如 AFD_FCB)
_In_opt_ CONNECTION_CONTEXT ConnectionContext,
_In_ ULONG ReceiveFlags, // TDI_RECEIVE_* 标志
_In_ ULONG BytesIndicated, // 当前指示的字节数
_In_ ULONG BytesAvailable, // 总可用字节数
_Out_ ULONG *BytesTaken, // 客户端取走的字节数
_In_ PVOID Tsdu, // 数据指针
_Out_opt_ PIRP *IoRequestPacket); // 可选: 客户端提供的接收 IRP
PTDI_IND_CONNECT --- 连接请求
c
typedef NTSTATUS (NTAPI *PTDI_IND_CONNECT)(
_In_opt_ PVOID TdiEventContext,
_In_ LONG RemoteAddressLength,
_In_ PVOID RemoteAddress, // 请求方地址
_In_ LONG UserDataLength,
_In_ PVOID UserData,
_In_ LONG OptionsLength,
_In_ PVOID Options,
_Out_ CONNECTION_CONTEXT *ConnectionContext, // 输出连接上下文
_Out_ PIRP *AcceptIrp); // 输出接受 IRP
PTDI_IND_DISCONNECT --- 断开
c
typedef NTSTATUS (NTAPI *PTDI_IND_DISCONNECT)(
_In_opt_ PVOID TdiEventContext,
_In_opt_ CONNECTION_CONTEXT ConnectionContext,
_In_ LONG DisconnectDataLength,
_In_ PVOID DisconnectData,
_In_ LONG DisconnectInformationLength,
_In_ PVOID DisconnectInformation,
_In_ ULONG DisconnectFlags); // TDI_DISCONNECT_*
6.3 事件处理流程(数据到达为例)
传输驱动 (tcpip.sys)
│
│ 收到数据 → 查找连接端点的事件处理器
▼
调用 TDI_EVENT_RECEIVE 处理器
│
├─ 客户端在回调中:
│ ├─ 复制 Tsdu 数据到自己的缓冲
│ ├─ 设置 *BytesTaken = 实际取走的字节数
│ └─ 返回 STATUS_SUCCESS
│
├─ 返回 STATUS_MORE_PROCESSING_REQUIRED 表示保留数据
│
└─ 客户端可以选择提供 IoRequestPacket (自己的接收 IRP)
└─ 传输驱动用该 IRP 完成剩余数据的传输
6.4 默认处理器
tdikrnl.h 导出了默认事件处理器(供客户端继承后调用):
| 默认处理器 | 对应事件 |
|---|---|
TdiDefaultConnectHandler |
TDI_EVENT_CONNECT |
TdiDefaultDisconnectHandler |
TDI_EVENT_DISCONNECT |
TdiDefaultErrorHandler |
TDI_EVENT_ERROR |
TdiDefaultReceiveHandler |
TDI_EVENT_RECEIVE |
TdiDefaultRcvDatagramHandler |
TDI_EVENT_RECEIVE_DATAGRAM |
TdiDefaultRcvExpeditedHandler |
TDI_EVENT_RECEIVE_EXPEDITED |
TdiDefaultChainedReceiveHandler |
TDI_EVENT_CHAINED_RECEIVE |
TdiDefaultChainedRcvDatagramHandler |
TDI_EVENT_CHAINED_RECEIVE_DATAGRAM |
TdiDefaultChainedRcvExpeditedHandler |
TDI_EVENT_CHAINED_RECEIVE_EXPEDITED |
TdiDefaultSendPossibleHandler |
TDI_EVENT_SEND_POSSIBLE |
7. TDI IRP 构建机制 (TdiBuild*)
7.1 TdiBuildBaseIrp --- 基础构建宏
定义在 tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h#L391-L404):
c
#define TdiBuildBaseIrp(bIrp, bDevObj, bFileObj, bCompRoutine, bContxt, bIrpSp, bMinor) \
{ \
bIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; \
bIrpSp->MinorFunction = (bMinor); \
bIrpSp->DeviceObject = (bDevObj); \
bIrpSp->FileObject = (bFileObj); \
if (bCompRoutine) \
IoSetCompletionRoutine(bIrp, bCompRoutine, bContxt, TRUE, TRUE, TRUE);\
else \
IoSetCompletionRoutine(bIrp, NULL, NULL, FALSE, FALSE, FALSE); \
}
7.2 TdiBuildInternalDeviceControlIrp --- 分配 IRP
c
#define TdiBuildInternalDeviceControlIrp(IrpSubFunction, DeviceObject, \
FileObject, Event, IoStatusBlock) \
IoBuildDeviceIoControlRequest( \
IrpSubFunction, // 传给 IoControlCode → 实际作为 MinorFunction
DeviceObject, // 目标设备
NULL, 0, NULL, 0, // 无输入输出缓冲
TRUE, // InternalDeviceIoControl = TRUE
Event, // 完成事件
IoStatusBlock) // IO 状态块
7.3 各操作构建宏汇总
| 宏 | 功能 |
|---|---|
TdiBuildAccept |
构建 TDI_ACCEPT 请求 |
TdiBuildAction |
构建 TDI_ACTION 请求 |
TdiBuildAssociateAddress |
构建 TDI_ASSOCIATE_ADDRESS |
TdiBuildConnect |
构建 TDI_CONNECT |
TdiBuildDisassociateAddress |
构建 TDI_DISASSOCIATE_ADDRESS |
TdiBuildDisconnect |
构建 TDI_DISCONNECT |
TdiBuildListen |
构建 TDI_LISTEN |
TdiBuildQueryInformation |
构建 TDI_QUERY_INFORMATION |
TdiBuildReceive |
构建 TDI_RECEIVE |
TdiBuildReceiveDatagram |
构建 TDI_RECEIVE_DATAGRAM |
TdiBuildSend |
构建 TDI_SEND |
TdiBuildSendDatagram |
构建 TDI_SEND_DATAGRAM |
TdiBuildSetEventHandler |
构建 TDI_SET_EVENT_HANDLER |
TdiBuildSetInformation |
构建 TDI_SET_INFORMATION |
7.4 TdiBuildSend 示例
c
#define TdiBuildSend(Irp, DevObj, FileObj, CompRoutine, Contxt, \
MdlAddr, InFlags, SendLen) \
{ \
PTDI_REQUEST_KERNEL_SEND _Request; \
PIO_STACK_LOCATION _IrpSp; \
\
_IrpSp = IoGetNextIrpStackLocation(Irp); \
TdiBuildBaseIrp(Irp, DevObj, FileObj, CompRoutine, \
Contxt, _IrpSp, TDI_SEND); \
_Request = (PTDI_REQUEST_KERNEL_SEND)&_IrpSp->Parameters; \
_Request->SendFlags = (InFlags); \
_Request->SendLength = (SendLen); \
(Irp)->MdlAddress = (MdlAddr); /* 数据缓冲 MDL */ \
}
7.5 TdiCompleteRequest --- 完成 TDI 请求
c
#define TdiCompleteRequest(Irp, Status) \
{ \
(Irp)->IoStatus.Status = (Status); \
IoCompleteRequest((Irp), IO_NETWORK_INCREMENT); \
}
7.6 数据复制辅助
c
TdiCopyBufferToMdl(...) // 缓冲区 → MDL 链
TdiCopyMdlToBuffer(...) // MDL 链 → 缓冲区
TdiCopyMdlChainToMdlChain(...) // MDL 链 → MDL 链
TdiCopyLookaheadData(...) // 前瞻数据复制 (= RtlCopyMemory)
TdiMapBuffer(...) / TdiUnmapBuffer(...) // MDL 映射
8. tdihelpers 库
ReactOS 的 tdihelpers 库封装了 TDI 操作,供 AFD.sys 使用。
8.1 TdiCall --- 调用传输驱动
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L26-L65):
TdiCall(Irp, DeviceObject, Event, Iosb)
│
├─ IoCallDriver(DeviceObject, Irp)
│ └─ 传输驱动的 MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
│
├─ STATUS_PENDING 且 Event != NULL:
│ └─ KeWaitForSingleObject(Event) // 同步等待
│ └─ 完成后读取 Iosb->Status
│
└─ 返回最终状态
8.2 TdiOpenDevice --- 打开设备
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L68-L146):
TdiOpenDevice(DeviceName, EaLength, EaInfo, ShareType, Handle, Object)
│
├─ InitializeObjectAttributes(DeviceName)
├─ ZwCreateFile(Handle, GENERIC_READ|WRITE|SYNCHRONIZE,
│ &Attr, &Iosb, 0, FILE_ATTRIBUTE_NORMAL,
│ ShareAccess, FILE_OPEN_IF, 0, EaInfo, EaLength)
├─ ObReferenceObjectByHandle(*Handle, ..., *IoFileObjectType,
│ ..., (PVOID*)Object)
└─ 返回句柄 + 文件对象指针
8.3 TdiOpenAddressFile --- 打开地址文件
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L148-L201):
TdiOpenAddressFile(DeviceName, Name, ShareType, AddressHandle, AddressObject)
│
├─ 构造 EA:
│ EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH
│ EaName = "TransportAddress"
│ EaValueLength = sizeof(TA_IP_ADDRESS)
│ EaValue = Name (TA_IP_ADDRESS)
│
├─ TdiOpenDevice(DeviceName, EaLength, EaInfo, ShareType, ...)
│
└─ 返回地址文件句柄 + 对象
8.4 TdiOpenConnectionEndpointFile --- 打开连接端点
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L258-L308):
TdiOpenConnectionEndpointFile(DeviceName, ConnectionHandle, ConnectionObject)
│
├─ 构造 EA:
│ EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH
│ EaName = "ConnectionContext"
│ EaValueLength = sizeof(PVOID)
│ EaValue = ContextArea (上下文指针)
│
├─ TdiOpenDevice(DeviceName, ..., AFD_SHARE_UNIQUE, ...)
│
└─ 返回连接端点句柄 + 对象
8.5 TdiAssociateAddressFile --- 关联地址
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L370-L411):
TdiAssociateAddressFile(AddressHandle, ConnectionObject)
│
├─ TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS, ...)
├─ TdiBuildAssociateAddress(Irp, DevObj, ConnObj, NULL, NULL, AddressHandle)
└─ TdiCall(Irp, DeviceObject, &Event, &Iosb)
8.6 TdiConnect --- 连接
实现在 tdiconn.c(file:///d:/reactos/drivers/network/tdihelpers/tdiconn.c) 和 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L311-L380):
TdiConnect(Irp, ConnectionObject, ConnectionCallInfo, ConnectionReturnInfo,
CompletionRoutine, CompletionContext)
│
├─ TdiBuildInternalDeviceControlIrp(TDI_CONNECT, ...)
├─ TdiBuildConnect(Irp, DevObj, ConnObj, CompletionRoutine,
│ CompletionContext, Time, CallInfo, ReturnInfo)
└─ IoCallDriver (异步, 返回 STATUS_PENDING)
8.7 TdiSetEventHandler --- 设置事件处理器
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L568-L626):
TdiSetEventHandler(FileObject, EventType, Handler, Context)
│
├─ TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, ...)
├─ TdiBuildSetEventHandler(Irp, DevObj, FileObj, NULL, NULL,
│ EventType, Handler, Context)
└─ TdiCall(Irp, DeviceObject, &Event, &Iosb)
8.8 TdiQueryDeviceControl --- 设备控制查询
实现在 tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L629-L700):
TdiQueryDeviceControl(FileObject, IoControlCode, ...)
│
├─ IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, ...)
└─ IoCallDriver
9. TDI 信息查询
9.1 通用查询类型
定义在 tdi.h(file:///d:/reactos/sdk/include/psdk/tdi.h#L179-L192):
c
#define TDI_QUERY_BROADCAST_ADDRESS 0x00000001 // 广播地址
#define TDI_QUERY_PROVIDER_INFO 0x00000002 // 提供者信息
#define TDI_QUERY_ADDRESS_INFO 0x00000003 // 地址信息
#define TDI_QUERY_CONNECTION_INFO 0x00000004 // 连接信息
#define TDI_QUERY_PROVIDER_STATISTICS 0x00000005 // 提供者统计
#define TDI_QUERY_DATAGRAM_INFO 0x00000006 // 数据报信息
#define TDI_QUERY_DATA_LINK_ADDRESS 0x00000007 // 链路层地址
#define TDI_QUERY_NETWORK_ADDRESS 0x00000008 // 网络地址
#define TDI_QUERY_MAX_DATAGRAM_INFO 0x00000009 // 最大数据报
9.2 结果结构
TDI_PROVIDER_INFO --- 提供者能力:
c
typedef struct _TDI_PROVIDER_INFO {
ULONG Version; // TDI 版本
ULONG MaxSendSize; // 最大发送大小
ULONG MaxConnectionUserData;// 最大连接用户数据
ULONG MaxDatagramSize; // 最大数据报大小
ULONG ServiceFlags; // 服务标志 (TDI_SERVICE_*)
ULONG MinimumLookaheadData; // 最小前瞻数据
ULONG MaximumLookaheadData; // 最大前瞻数据
ULONG NumberOfResources;
LARGE_INTEGER StartTime;
} TDI_PROVIDER_INFO, *PTDI_PROVIDER_INFO;
服务标志(部分):
c
#define TDI_SERVICE_CONNECTION_MODE 0x00000001 // 面向连接
#define TDI_SERVICE_ORDERLY_RELEASE 0x00000002 // 有序释放
#define TDI_SERVICE_CONNECTIONLESS_MODE 0x00000004 // 无连接
#define TDI_SERVICE_ERROR_FREE_DELIVERY 0x00000008 // 无错投递
#define TDI_SERVICE_BROADCAST_SUPPORTED 0x00000020 // 支持广播
#define TDI_SERVICE_MULTICAST_SUPPORTED 0x00000040 // 支持多播
#define TDI_SERVICE_EXPEDITED_DATA 0x00000100 // 紧急数据
#define TDI_SERVICE_INTERNAL_BUFFERING 0x00000200 // 内部缓冲
TDI_CONNECTION_INFO --- 连接状态:
c
typedef struct _TDI_CONNECTION_INFO {
ULONG State; // 连接状态
ULONG Event;
ULONG TransmittedTsdus; // 已发送 TSDU 数
ULONG ReceivedTsdus; // 已接收 TSDU 数
ULONG TransmissionErrors;
ULONG ReceiveErrors;
LARGE_INTEGER Throughput; // 吞吐量
LARGE_INTEGER Delay; // 延迟
ULONG SendBufferSize; // 发送缓冲大小
ULONG ReceiveBufferSize; // 接收缓冲大小
BOOLEAN Unreliable;
} TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO;
TDI_MAX_DATAGRAM_INFO --- 最大数据报:
c
typedef struct _TDI_MAX_DATAGRAM_INFO {
ULONG MaxDatagramSize;
} TDI_MAX_DATAGRAM_INFO, *PTDI_MAX_DATAGRAM_INFO;
9.3 在 tcpip.sys 中的实现
tcpip.sys 的 DispTdiQueryInformation 处理 TDI 查询:
| 查询类型 | 处理 |
|---|---|
TDI_QUERY_ADDRESS_INFO |
返回地址文件的 IP 和端口 |
TDI_QUERY_CONNECTION_INFO |
返回连接信息 |
TDI_QUERY_MAX_DATAGRAM_INFO |
返回 0xFFFF (65535) |
10. 工作流程图
10.1 地址文件打开流程
#mermaid-svg-dDO7itxYuplS7JOi{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-dDO7itxYuplS7JOi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dDO7itxYuplS7JOi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dDO7itxYuplS7JOi .error-icon{fill:#552222;}#mermaid-svg-dDO7itxYuplS7JOi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dDO7itxYuplS7JOi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dDO7itxYuplS7JOi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dDO7itxYuplS7JOi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dDO7itxYuplS7JOi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dDO7itxYuplS7JOi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dDO7itxYuplS7JOi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dDO7itxYuplS7JOi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dDO7itxYuplS7JOi .marker.cross{stroke:#333333;}#mermaid-svg-dDO7itxYuplS7JOi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dDO7itxYuplS7JOi p{margin:0;}#mermaid-svg-dDO7itxYuplS7JOi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dDO7itxYuplS7JOi .cluster-label text{fill:#333;}#mermaid-svg-dDO7itxYuplS7JOi .cluster-label span{color:#333;}#mermaid-svg-dDO7itxYuplS7JOi .cluster-label span p{background-color:transparent;}#mermaid-svg-dDO7itxYuplS7JOi .label text,#mermaid-svg-dDO7itxYuplS7JOi span{fill:#333;color:#333;}#mermaid-svg-dDO7itxYuplS7JOi .node rect,#mermaid-svg-dDO7itxYuplS7JOi .node circle,#mermaid-svg-dDO7itxYuplS7JOi .node ellipse,#mermaid-svg-dDO7itxYuplS7JOi .node polygon,#mermaid-svg-dDO7itxYuplS7JOi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dDO7itxYuplS7JOi .rough-node .label text,#mermaid-svg-dDO7itxYuplS7JOi .node .label text,#mermaid-svg-dDO7itxYuplS7JOi .image-shape .label,#mermaid-svg-dDO7itxYuplS7JOi .icon-shape .label{text-anchor:middle;}#mermaid-svg-dDO7itxYuplS7JOi .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dDO7itxYuplS7JOi .rough-node .label,#mermaid-svg-dDO7itxYuplS7JOi .node .label,#mermaid-svg-dDO7itxYuplS7JOi .image-shape .label,#mermaid-svg-dDO7itxYuplS7JOi .icon-shape .label{text-align:center;}#mermaid-svg-dDO7itxYuplS7JOi .node.clickable{cursor:pointer;}#mermaid-svg-dDO7itxYuplS7JOi .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dDO7itxYuplS7JOi .arrowheadPath{fill:#333333;}#mermaid-svg-dDO7itxYuplS7JOi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dDO7itxYuplS7JOi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dDO7itxYuplS7JOi .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dDO7itxYuplS7JOi .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dDO7itxYuplS7JOi .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dDO7itxYuplS7JOi .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dDO7itxYuplS7JOi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dDO7itxYuplS7JOi .cluster text{fill:#333;}#mermaid-svg-dDO7itxYuplS7JOi .cluster span{color:#333;}#mermaid-svg-dDO7itxYuplS7JOi 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-dDO7itxYuplS7JOi .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dDO7itxYuplS7JOi rect.text{fill:none;stroke-width:0;}#mermaid-svg-dDO7itxYuplS7JOi .icon-shape,#mermaid-svg-dDO7itxYuplS7JOi .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dDO7itxYuplS7JOi .icon-shape p,#mermaid-svg-dDO7itxYuplS7JOi .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dDO7itxYuplS7JOi .icon-shape .label rect,#mermaid-svg-dDO7itxYuplS7JOi .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dDO7itxYuplS7JOi .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dDO7itxYuplS7JOi .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dDO7itxYuplS7JOi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
客户端需要绑定地址
TdiOpenAddressFile
构造 FILE_FULL_EA_INFORMATION
EaName = TransportAddress
EaValue = TA_IP_ADDRESS
ZwCreateFile \\Device\\Tcp
IRP_MJ_CREATE → tcpip.sys
TiCreateFileObject
EA 是 TransportAddress?
解析 TA_IP_ADDRESS
FileOpenAddress
创建 ADDRESS_FILE
分配端口
FsContext2 = TDI_TRANSPORT_ADDRESS_FILE
返回地址文件句柄
10.2 连接建立流程
#mermaid-svg-MLVKkQej1sgy1rl4{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-MLVKkQej1sgy1rl4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MLVKkQej1sgy1rl4 .error-icon{fill:#552222;}#mermaid-svg-MLVKkQej1sgy1rl4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MLVKkQej1sgy1rl4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MLVKkQej1sgy1rl4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MLVKkQej1sgy1rl4 .marker.cross{stroke:#333333;}#mermaid-svg-MLVKkQej1sgy1rl4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MLVKkQej1sgy1rl4 p{margin:0;}#mermaid-svg-MLVKkQej1sgy1rl4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 .cluster-label text{fill:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 .cluster-label span{color:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 .cluster-label span p{background-color:transparent;}#mermaid-svg-MLVKkQej1sgy1rl4 .label text,#mermaid-svg-MLVKkQej1sgy1rl4 span{fill:#333;color:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 .node rect,#mermaid-svg-MLVKkQej1sgy1rl4 .node circle,#mermaid-svg-MLVKkQej1sgy1rl4 .node ellipse,#mermaid-svg-MLVKkQej1sgy1rl4 .node polygon,#mermaid-svg-MLVKkQej1sgy1rl4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MLVKkQej1sgy1rl4 .rough-node .label text,#mermaid-svg-MLVKkQej1sgy1rl4 .node .label text,#mermaid-svg-MLVKkQej1sgy1rl4 .image-shape .label,#mermaid-svg-MLVKkQej1sgy1rl4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-MLVKkQej1sgy1rl4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MLVKkQej1sgy1rl4 .rough-node .label,#mermaid-svg-MLVKkQej1sgy1rl4 .node .label,#mermaid-svg-MLVKkQej1sgy1rl4 .image-shape .label,#mermaid-svg-MLVKkQej1sgy1rl4 .icon-shape .label{text-align:center;}#mermaid-svg-MLVKkQej1sgy1rl4 .node.clickable{cursor:pointer;}#mermaid-svg-MLVKkQej1sgy1rl4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MLVKkQej1sgy1rl4 .arrowheadPath{fill:#333333;}#mermaid-svg-MLVKkQej1sgy1rl4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MLVKkQej1sgy1rl4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MLVKkQej1sgy1rl4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MLVKkQej1sgy1rl4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MLVKkQej1sgy1rl4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MLVKkQej1sgy1rl4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MLVKkQej1sgy1rl4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MLVKkQej1sgy1rl4 .cluster text{fill:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 .cluster span{color:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 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-MLVKkQej1sgy1rl4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MLVKkQej1sgy1rl4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-MLVKkQej1sgy1rl4 .icon-shape,#mermaid-svg-MLVKkQej1sgy1rl4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MLVKkQej1sgy1rl4 .icon-shape p,#mermaid-svg-MLVKkQej1sgy1rl4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MLVKkQej1sgy1rl4 .icon-shape .label rect,#mermaid-svg-MLVKkQej1sgy1rl4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MLVKkQej1sgy1rl4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MLVKkQej1sgy1rl4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MLVKkQej1sgy1rl4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端发起连接
TdiOpenConnectionEndpointFile
ZwCreateFile + ConnectionContext EA
tcpip.sys 创建连接端点
TdiAssociateAddressFile
TDI_ASSOCIATE_ADDRESS IRP
关联地址文件与连接
TdiSetEventHandler 注册事件
TDI_SET_EVENT_HANDLER
保存回调函数
TdiConnect
TdiBuildConnect TDI_CONNECT
IoCallDriver
tcpip.sys DispTdiConnect
TCPConnect 发送 SYN
等待 SYN+ACK
ESTABLISHED
完成 TDI IRP
客户端连接成功
10.3 数据发送流程
#mermaid-svg-xWVwbrqbFVDT2FtS{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-xWVwbrqbFVDT2FtS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xWVwbrqbFVDT2FtS .error-icon{fill:#552222;}#mermaid-svg-xWVwbrqbFVDT2FtS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xWVwbrqbFVDT2FtS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xWVwbrqbFVDT2FtS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xWVwbrqbFVDT2FtS .marker.cross{stroke:#333333;}#mermaid-svg-xWVwbrqbFVDT2FtS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xWVwbrqbFVDT2FtS p{margin:0;}#mermaid-svg-xWVwbrqbFVDT2FtS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS .cluster-label text{fill:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS .cluster-label span{color:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS .cluster-label span p{background-color:transparent;}#mermaid-svg-xWVwbrqbFVDT2FtS .label text,#mermaid-svg-xWVwbrqbFVDT2FtS span{fill:#333;color:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS .node rect,#mermaid-svg-xWVwbrqbFVDT2FtS .node circle,#mermaid-svg-xWVwbrqbFVDT2FtS .node ellipse,#mermaid-svg-xWVwbrqbFVDT2FtS .node polygon,#mermaid-svg-xWVwbrqbFVDT2FtS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xWVwbrqbFVDT2FtS .rough-node .label text,#mermaid-svg-xWVwbrqbFVDT2FtS .node .label text,#mermaid-svg-xWVwbrqbFVDT2FtS .image-shape .label,#mermaid-svg-xWVwbrqbFVDT2FtS .icon-shape .label{text-anchor:middle;}#mermaid-svg-xWVwbrqbFVDT2FtS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xWVwbrqbFVDT2FtS .rough-node .label,#mermaid-svg-xWVwbrqbFVDT2FtS .node .label,#mermaid-svg-xWVwbrqbFVDT2FtS .image-shape .label,#mermaid-svg-xWVwbrqbFVDT2FtS .icon-shape .label{text-align:center;}#mermaid-svg-xWVwbrqbFVDT2FtS .node.clickable{cursor:pointer;}#mermaid-svg-xWVwbrqbFVDT2FtS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xWVwbrqbFVDT2FtS .arrowheadPath{fill:#333333;}#mermaid-svg-xWVwbrqbFVDT2FtS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xWVwbrqbFVDT2FtS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xWVwbrqbFVDT2FtS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xWVwbrqbFVDT2FtS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xWVwbrqbFVDT2FtS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xWVwbrqbFVDT2FtS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xWVwbrqbFVDT2FtS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xWVwbrqbFVDT2FtS .cluster text{fill:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS .cluster span{color:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS 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-xWVwbrqbFVDT2FtS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xWVwbrqbFVDT2FtS rect.text{fill:none;stroke-width:0;}#mermaid-svg-xWVwbrqbFVDT2FtS .icon-shape,#mermaid-svg-xWVwbrqbFVDT2FtS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xWVwbrqbFVDT2FtS .icon-shape p,#mermaid-svg-xWVwbrqbFVDT2FtS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xWVwbrqbFVDT2FtS .icon-shape .label rect,#mermaid-svg-xWVwbrqbFVDT2FtS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xWVwbrqbFVDT2FtS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xWVwbrqbFVDT2FtS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xWVwbrqbFVDT2FtS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端发送数据
构造数据 MDL
TdiBuildSend TDI_SEND
Irp->MdlAddress = 数据缓冲
IoCallDriver
tcpip.sys DispTdiSend
TCPSendData
TCP 分段 → IP → LAN → NdisSend
发送完成
IoCompleteRequest
客户端完成回调
10.4 数据接收事件流程
#mermaid-svg-ydpd1LqyzhHvpCnm{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-ydpd1LqyzhHvpCnm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ydpd1LqyzhHvpCnm .error-icon{fill:#552222;}#mermaid-svg-ydpd1LqyzhHvpCnm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ydpd1LqyzhHvpCnm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ydpd1LqyzhHvpCnm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ydpd1LqyzhHvpCnm .marker.cross{stroke:#333333;}#mermaid-svg-ydpd1LqyzhHvpCnm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ydpd1LqyzhHvpCnm p{margin:0;}#mermaid-svg-ydpd1LqyzhHvpCnm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm .cluster-label text{fill:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm .cluster-label span{color:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm .cluster-label span p{background-color:transparent;}#mermaid-svg-ydpd1LqyzhHvpCnm .label text,#mermaid-svg-ydpd1LqyzhHvpCnm span{fill:#333;color:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm .node rect,#mermaid-svg-ydpd1LqyzhHvpCnm .node circle,#mermaid-svg-ydpd1LqyzhHvpCnm .node ellipse,#mermaid-svg-ydpd1LqyzhHvpCnm .node polygon,#mermaid-svg-ydpd1LqyzhHvpCnm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ydpd1LqyzhHvpCnm .rough-node .label text,#mermaid-svg-ydpd1LqyzhHvpCnm .node .label text,#mermaid-svg-ydpd1LqyzhHvpCnm .image-shape .label,#mermaid-svg-ydpd1LqyzhHvpCnm .icon-shape .label{text-anchor:middle;}#mermaid-svg-ydpd1LqyzhHvpCnm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ydpd1LqyzhHvpCnm .rough-node .label,#mermaid-svg-ydpd1LqyzhHvpCnm .node .label,#mermaid-svg-ydpd1LqyzhHvpCnm .image-shape .label,#mermaid-svg-ydpd1LqyzhHvpCnm .icon-shape .label{text-align:center;}#mermaid-svg-ydpd1LqyzhHvpCnm .node.clickable{cursor:pointer;}#mermaid-svg-ydpd1LqyzhHvpCnm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ydpd1LqyzhHvpCnm .arrowheadPath{fill:#333333;}#mermaid-svg-ydpd1LqyzhHvpCnm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ydpd1LqyzhHvpCnm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ydpd1LqyzhHvpCnm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ydpd1LqyzhHvpCnm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ydpd1LqyzhHvpCnm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ydpd1LqyzhHvpCnm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ydpd1LqyzhHvpCnm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ydpd1LqyzhHvpCnm .cluster text{fill:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm .cluster span{color:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm 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-ydpd1LqyzhHvpCnm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ydpd1LqyzhHvpCnm rect.text{fill:none;stroke-width:0;}#mermaid-svg-ydpd1LqyzhHvpCnm .icon-shape,#mermaid-svg-ydpd1LqyzhHvpCnm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ydpd1LqyzhHvpCnm .icon-shape p,#mermaid-svg-ydpd1LqyzhHvpCnm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ydpd1LqyzhHvpCnm .icon-shape .label rect,#mermaid-svg-ydpd1LqyzhHvpCnm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ydpd1LqyzhHvpCnm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ydpd1LqyzhHvpCnm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ydpd1LqyzhHvpCnm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
数据到达
tcpip.sys TCPReceive
查找连接端点
已注册 TDI_EVENT_RECEIVE?
调用客户端 ReceiveHandler
客户端复制 Tsdu 数据
设置 BytesTaken
返回 STATUS_SUCCESS
数据留在接收队列
tcpip.sys 确认数据已取走
11. 数据流图
11.1 TDI 完整调用链
TDI 客户端 (AFD.sys)
│
│ 1. ZwCreateFile(\Device\Tcp, EA=TransportAddress)
│ ── IRP_MJ_CREATE ──▶ tcpip.sys: TiCreateFileObject
│ └─ FileOpenAddress → ADDRESS_FILE
│
│ 2. ZwCreateFile(\Device\Tcp, EA=ConnectionContext)
│ ── IRP_MJ_CREATE ──▶ tcpip.sys: FileOpenConnection
│ └─ CONNECTION_ENDPOINT
│
│ 3. TdiAssociateAddressFile
│ ── IRP_MJ_INTERNAL_DEVICE_CONTROL (TDI_ASSOCIATE_ADDRESS)
│ ──▶ tcpip.sys: DispTdiAssociateAddress
│
│ 4. TdiSetEventHandler(TDI_EVENT_RECEIVE, ...)
│ ── TDI_SET_EVENT_HANDLER ──▶ tcpip.sys: DispTdiSetEventHandler
│
│ 5. TdiConnect
│ ── TDI_CONNECT ──▶ tcpip.sys: DispTdiConnect → TCPConnect
│
│ 6. TdiSend (数据+MDL)
│ ── TDI_SEND ──▶ tcpip.sys: DispTdiSend → TCPSendData
│
│ 7. 数据到达
│ ◀── TDI_EVENT_RECEIVE ── tcpip.sys 回调 AFD 的处理器
│
│ 8. TdiReceive (接收 MDL)
│ ── TDI_RECEIVE ──▶ tcpip.sys: DispTdiReceive → TCPReceiveData
│
│ 9. TdiDisconnect
│ ── TDI_DISCONNECT ──▶ tcpip.sys: DispTdiDisconnect → TCPDisconnect
11.2 TDI_SEND 请求结构
IRP (TDI_SEND)
├── MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL
├── MinorFunction = 0x07 (TDI_SEND)
├── MdlAddress = 数据缓冲 (MDL 链)
├── FileObject = 连接端点文件对象
├── DeviceObject = \Device\Tcp 设备
└── IrpSp->Parameters:
└── TDI_REQUEST_KERNEL_SEND
├── SendLength = 待发送字节数
└── SendFlags = TDI_SEND_* 标志
11.3 TDI 事件注册与触发
注册阶段:
客户端 ── TDI_SET_EVENT_HANDLER ──▶ tcpip.sys
{ EventType: TDI_EVENT_RECEIVE }
{ EventHandler: AfdEventReceive }
{ EventContext: AFD_FCB }
│
▼
ADDRESS_FILE 保存
{ RegisteredReceiveHandler = TRUE
ReceiveHandler = AfdEventReceive
ReceiveHandlerContext = FCB }
触发阶段:
数据到达
│
▼
tcpip.sys 查找 ADDRESS_FILE 的 ReceiveHandler
│
▼
调用 AfdEventReceive(FCB, ConnContext, Flags,
BytesIndicated, BytesAvailable,
&BytesTaken, Tsdu, &Irp)
│
├─ 复制数据到 FCB 缓冲
├─ *BytesTaken = BytesAvailable
└─ 返回 STATUS_SUCCESS
12. 关键定义索引
12.1 头文件
| 头文件 | 路径 | 内容 |
|---|---|---|
tdikrnl.h |
sdk/include/ddk/tdikrnl.h(file:///d:/reactos/sdk/include/ddk/tdikrnl.h) | 内核 TDI:请求码、TdiBuild 宏、事件原型 |
tdi.h |
sdk/include/psdk/tdi.h(file:///d:/reactos/sdk/include/psdk/tdi.h) | TDI 结构:连接信息、传输地址、查询类型 |
tdistat.h |
sdk/include/ddk/tdistat.h(file:///d:/reactos/sdk/include/ddk/tdistat.h) | TDI 状态码 |
ntddtdi.h |
sdk/include/psdk/ntddtdi.h(file:///d:/reactos/sdk/include/psdk/ntddtdi.h) | TDI IOCTL 定义 |
tdiinfo.h |
sdk/include/psdk/tdiinfo.h(file:///d:/reactos/sdk/include/psdk/tdiinfo.h) | TDI 信息类 |
12.2 tdihelpers 函数
| 函数 | 位置 | 说明 |
|---|---|---|
TdiCall |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L26-L65) | IoCallDriver + 事件等待 |
TdiOpenDevice |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L68-L146) | 打开 TDI 设备 |
TdiOpenAddressFile |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L148-L201) | 打开地址文件 (EA) |
TdiQueryMaxDatagramLength |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L203-L256) | 查询最大数据报 |
TdiOpenConnectionEndpointFile |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L258-L308) | 打开连接端点 (EA) |
TdiConnect |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L311-L380) | TDI_CONNECT |
TdiAssociateAddressFile |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L370-L411) | TDI_ASSOCIATE_ADDRESS |
TdiDisassociateAddressFile |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L413-L458) | TDI_DISASSOCIATE_ADDRESS |
TdiListen |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L460-L512) | TDI_LISTEN |
TdiAccept |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L514-L565) | TDI_ACCEPT |
TdiSetEventHandler |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L568-L626) | TDI_SET_EVENT_HANDLER |
TdiQueryDeviceControl |
tdi.c(file:///d:/reactos/drivers/network/tdihelpers/tdi.c#L629-L700) | 设备控制查询 |
12.3 tcpip.sys 中的 TDI 处理
| TDI 操作 | tcpip.sys 处理函数 |
|---|---|
TDI_CONNECT |
DispTdiConnect → TCPConnect |
TDI_LISTEN |
DispTdiListen → TCPListen + TCPAccept |
TDI_ACCEPT |
DispTdiAccept |
TDI_DISCONNECT |
DispTdiDisconnect → TCPDisconnect |
TDI_SEND |
DispTdiSend → TCPSendData |
TDI_RECEIVE |
DispTdiReceive → TCPReceiveData |
TDI_SEND_DATAGRAM |
DispTdiSendDatagram |
TDI_RECEIVE_DATAGRAM |
DispTdiReceiveDatagram → DGReceiveDatagram |
TDI_SET_EVENT_HANDLER |
DispTdiSetEventHandler |
TDI_QUERY_INFORMATION |
DispTdiQueryInformation |
TDI_ASSOCIATE_ADDRESS |
DispTdiAssociateAddress |
TDI_DISASSOCIATE_ADDRESS |
DispTdiDisassociateAddress |
12.4 参考文档
- TCPIP 驱动分析(file:///d:/reactos/doc/TCPIP_驱动分析.md) --- tcpip.sys 中的 TDI 分发处理
- AFD辅助功能驱动分析(file:///d:/reactos/doc/AFD辅助功能驱动分析.md) --- AFD.sys 作为 TDI 客户端
- WSP服务提供者AFD_Provider分析(file:///d:/reactos/doc/WSP服务提供者AFD_Provider分析.md) --- msafd.dll
- TCP/IP协议驱动分析_1.md(file:///d:/reactos/doc/TCP/IP协议驱动分析_1.md) --- 完整调用链