首先来介绍一下AFD驱动。大家可能对NDIS及TDI了解的比较多,AFD驱动相对会少一些。NDIS及TDI是微软提供的内核网络驱动模型中的编程接口规范,而AFD驱动是微软Windows操作一个驱动部件。它是上层SOCKET在内核心中的实现。我这里画了一个图例来说明它们之间的关系:
简来说AFD驱动向上与SOCKET应用接口约定了接口来实现SOCKET,AFD驱动实际上是一个TDI客户端,它通过TDI接口调用微软件的另一个网络部件TCPIP驱动来完成功能。AFD并没有官方的资料说明它的接口,但是在网上还是可以找到很关于AFD驱动的资料的。这里笔者参考了ReactOS-0.3.4-REL-src源代码中的AFD的内容,它于官方的AFD驱动实现还是有一些驱动别的,比如未实现FASTIO接口等。
在AFD中它主要处理如下IO控制码,上层的应用也主要是通过它们来完成SOCKET各种操作。
/* IOCTL Generation */
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
#define _AFD_CONTROL_CODE(Operation,Method) /
((FSCTL_AFD_BASE)<<12 | (Operation<<2) | Method)
/* AFD Commands */
#define AFD_BIND 0
#define AFD_CONNECT 1
#define AFD_START_LISTEN 2
#define AFD_WAIT_FOR_LISTEN 3
#define AFD_ACCEPT 4
#define AFD_RECV 5
#define AFD_RECV_DATAGRAM 6
#define AFD_SEND 7
#define AFD_SEND_DATAGRAM 8
#define AFD_SELECT 9
#define AFD_DISCONNECT 10
#define AFD_GET_SOCK_NAME 11
#define AFD_GET_PEER_NAME 12
#define AFD_GET_TDI_HANDLES 13
#define AFD_SET_INFO 14
#define AFD_GET_CONTEXT 16
#define AFD_SET_CONTEXT 17
#define AFD_SET_CONNECT_DATA 18
#define AFD_SET_CONNECT_OPTIONS 19
#define AFD_SET_DISCONNECT_DATA 20
#define AFD_SET_DISCONNECT_OPTIONS 21
#define AFD_GET_CONNECT_DATA 22
#define AFD_GET_CONNECT_OPTIONS 23
#define AFD_GET_DISCONNECT_DATA 24
#define AFD_GET_DISCONNECT_OPTIONS 25
#define AFD_SET_CONNECT_DATA_SIZE 26
#define AFD_SET_CONNECT_OPTIONS_SIZE 27
#define AFD_SET_DISCONNECT_DATA_SIZE 28
#define AFD_SET_DISCONNECT_OPTIONS_SIZE 29
#define AFD_GET_INFO 30
#define AFD_EVENT_SELECT 33
#define AFD_ENUM_NETWORK_EVENTS 34
#define AFD_DEFER_ACCEPT 35
#define AFD_GET_PENDING_CONNECT_DATA 41
/* AFD IOCTLs */
#define IOCTL_AFD_BIND /
_AFD_CONTROL_CODE(AFD_BIND, METHOD_NEITHER)
#define IOCTL_AFD_CONNECT /
_AFD_CONTROL_CODE(AFD_CONNECT, METHOD_NEITHER)
#define IOCTL_AFD_START_LISTEN /
_AFD_CONTROL_CODE(AFD_START_LISTEN, METHOD_NEITHER)
#define IOCTL_AFD_WAIT_FOR_LISTEN /
_AFD_CONTROL_CODE(AFD_WAIT_FOR_LISTEN, METHOD_BUFFERED )
#define IOCTL_AFD_ACCEPT /
_AFD_CONTROL_CODE(AFD_ACCEPT, METHOD_BUFFERED )
#define IOCTL_AFD_RECV /
_AFD_CONTROL_CODE(AFD_RECV, METHOD_NEITHER)
#define IOCTL_AFD_RECV_DATAGRAM /
_AFD_CONTROL_CODE(AFD_RECV_DATAGRAM, METHOD_NEITHER)
#define IOCTL_AFD_SEND /
_AFD_CONTROL_CODE(AFD_SEND, METHOD_NEITHER)
#define IOCTL_AFD_SEND_DATAGRAM /
_AFD_CONTROL_CODE(AFD_SEND_DATAGRAM, METHOD_NEITHER)
#define IOCTL_AFD_SELECT /
_AFD_CONTROL_CODE(AFD_SELECT, METHOD_BUFFERED )
#define IOCTL_AFD_DISCONNECT /
_AFD_CONTROL_CODE(AFD_DISCONNECT, METHOD_NEITHER)
#define IOCTL_AFD_GET_SOCK_NAME /
_AFD_CONTROL_CODE(AFD_GET_SOCK_NAME, METHOD_NEITHER)
#define IOCTL_AFD_GET_PEER_NAME /
_AFD_CONTROL_CODE(AFD_GET_PEER_NAME, METHOD_NEITHER)
#define IOCTL_AFD_GET_TDI_HANDLES /
_AFD_CONTROL_CODE(AFD_GET_TDI_HANDLES, METHOD_NEITHER)
#define IOCTL_AFD_SET_INFO /
_AFD_CONTROL_CODE(AFD_SET_INFO, METHOD_NEITHER)
#define IOCTL_AFD_GET_CONTEXT /
_AFD_CONTROL_CODE(AFD_GET_CONTEXT, METHOD_NEITHER)
#define IOCTL_AFD_SET_CONTEXT /
_AFD_CONTROL_CODE(AFD_SET_CONTEXT, METHOD_NEITHER)
#define IOCTL_AFD_SET_CONNECT_DATA /
_AFD_CONTROL_CODE(AFD_SET_CONNECT_DATA, METHOD_NEITHER)
#define IOCTL_AFD_SET_CONNECT_OPTIONS /
_AFD_CONTROL_CODE(AFD_SET_CONNECT_OPTIONS, METHOD_NEITHER)
#define IOCTL_AFD_SET_DISCONNECT_DATA /
_AFD_CONTROL_CODE(AFD_SET_DISCONNECT_DATA, METHOD_NEITHER)
#define IOCTL_AFD_SET_DISCONNECT_OPTIONS /
_AFD_CONTROL_CODE(AFD_SET_DISCONNECT_OPTIONS, METHOD_NEITHER)
#define IOCTL_AFD_GET_CONNECT_DATA /
_AFD_CONTROL_CODE(AFD_GET_CONNECT_DATA, METHOD_NEITHER)
#define IOCTL_AFD_GET_CONNECT_OPTIONS /
_AFD_CONTROL_CODE(AFD_GET_CONNECT_OPTIONS, METHOD_NEITHER)
#define IOCTL_AFD_GET_DISCONNECT_DATA /
_AFD_CONTROL_CODE(AFD_GET_DISCONNECT_DATA, METHOD_NEITHER)
#define IOCTL_AFD_GET_DISCONNECT_OPTIONS /
_AFD_CONTROL_CODE(AFD_GET_DISCONNECT_OPTIONS, METHOD_NEITHER)
#define IOCTL_AFD_SET_CONNECT_DATA_SIZE /
_AFD_CONTROL_CODE(AFD_SET_CONNECT_DATA_SIZE, METHOD_NEITHER)
#define IOCTL_AFD_SET_CONNECT_OPTIONS_SIZE /
_AFD_CONTROL_CODE(AFD_SET_CONNECT_OPTIONS_SIZE, METHOD_NEITHER)
#define IOCTL_AFD_SET_DISCONNECT_DATA_SIZE /
_AFD_CONTROL_CODE(AFD_SET_DISCONNECT_DATA_SIZE, METHOD_NEITHER)
#define IOCTL_AFD_SET_DISCONNECT_OPTIONS_SIZE /
_AFD_CONTROL_CODE(AFD_SET_DISCONNECT_OPTIONS_SIZE, METHOD_NEITHER)
#define IOCTL_AFD_GET_INFO /
_AFD_CONTROL_CODE(AFD_GET_INFO, METHOD_NEITHER)
#define IOCTL_AFD_EVENT_SELECT /
_AFD_CONTROL_CODE(AFD_EVENT_SELECT, METHOD_NEITHER)
#define IOCTL_AFD_DEFER_ACCEPT /
_AFD_CONTROL_CODE(AFD_DEFER_ACCEPT, METHOD_NEITHER)
#define IOCTL_AFD_GET_PENDING_CONNECT_DATA /
_AFD_CONTROL_CODE(AFD_GET_PENDING_CONNECT_DATA, METHOD_NEITHER)
#define IOCTL_AFD_ENUM_NETWORK_EVENTS /
_AFD_CONTROL_CODE(AFD_ENUM_NETWORK_EVENTS, METHOD_NEITHER)
可以通过名称看出这些IO控制码,对应了我们常用的SOCKET API。而我们要关注仅仅是的其中的一部分,下面就对我们完成流量控制要关注的IO控制码做一下简单介绍。在这些IO控制码中和发送和接收相关的有四个,它会分别是IOCTL_AFD_SEND、IOCTL_AFD_SEND_DATAGRAM、IOCTL_AFD_RECV、IOCTL_AFD_RECV_DATAGRAM。它们分别用于发送带链接的数据、发送非面向链接的数据包、接收面向链接的数据包、接收非面向链接的数据包。这四个IO控制码进行数据发送和接收时还涉及一些数据结构。这些在后面介绍流量控制时会用到。先在这里说明一下。
typedef struct _AFD_MAPBUF {
PVOID BufferAddress;
PMDL Mdl;
} AFD_MAPBUF, *PAFD_MAPBUF;
typedef struct _AFD_WSABUF {
UINT len;
PCHAR buf;
} AFD_WSABUF, *PAFD_WSABUF;
typedef struct _AFD_RECV_INFO {
PAFD_WSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
ULONG TdiFlags;
} AFD_RECV_INFO , *PAFD_RECV_INFO ;
typedef struct _AFD_RECV_INFO_UDP {
PAFD_WSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
ULONG TdiFlags;
PVOID Address;
PINT AddressLength;
} AFD_RECV_INFO_UDP, *PAFD_RECV_INFO_UDP;
typedef struct _AFD_SEND_INFO {
PAFD_WSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
ULONG TdiFlags;
} AFD_SEND_INFO , *PAFD_SEND_INFO ;
typedef struct _AFD_SEND_INFO_UDP {
PAFD_WSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
ULONG Padding[9];
ULONG SizeOfRemoteAddress;
PVOID RemoteAddress;
} AFD_SEND_INFO_UDP, *PAFD_SEND_INFO_UDP;
其中IOCTL_AFD_SEND,IOCTL_AFD_RECV对应用结构为AFD_SEND_INFO和AFD_RECV_INFO,了解这两个结构我们仅仅是为了知道某次发送或接收的数据长度是多少。这两个结构中都有两个相同的域BufferArray和BufferCount,它们标识了发送或接收的缓冲区信息。AFD_WSABUF结构中len成员标识了一个缓冲区的长度,只要把某次发送或接收操作的BufferCount个缓冲区的长度累加就是本次发送和接收操作数据的总长度。
其中IOCTL_AFD_SEND_DATAGRAM,IOCTL_AFD_RECV_DATAGRAM对应用结构为AFD_SEND_INFO_UDP和AFD_RECV_INFO_UDP。这两个结构中也是都有两个相同的域BufferArray和BufferCount,它们标识了发送或接收的缓冲区信息。AFD_WSABUF结构中len成员标识了一个缓冲区的长度,只要把某次发送或接收操作的BufferCount个缓冲区的长度累加就是本次发送和接收操作数据的总长度。这和IOCTL_AFD_SEND,IOCTL_AFD_RECV对的结构一样的情况。