NDIS中间层驱动开发在Win7系统下和Windows XP系统下的区别

标 题: 【原创】NDIS中间层驱动开发在Win7系统下和Windows XP系统下的区别
作 者: tianhz
时 间: 2011-07-21,14:58:04
链 接: http://bbs.pediy.com/showthread.php?t=137545

NDIS中间层驱动的开发在Win7系统上和Windows XP系统上有差别。

我把NDIS中间层的讨论分成2块。 windows 7系统和Windows XP系统。

()在 Windows XP系统上进行开发
平时很多朋友包括我在内,我们都在XP系统上使用NDIS5.1的框架来进行程序开发。我们都使用
Microsoft WDK提供的 NDIS 的 Passthru例子,在这个例子上做进一步的修改,来达到我们的目地。

Passthru工程的 DriverEntry函数里面,我们都看见如下的代码:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NDIS_STATUS Status;
NDIS_PROTOCOL_CHARACTERISTICS PChars;
NDIS_MINIPORT_CHARACTERISTICS MChars;
PNDIS_CONFIGURATION_PARAMETER Param;
NDIS_STRING Name;
NDIS_HANDLE WrapperHandle;


UNICODE_STRING nameString, linkString; 
UINT FuncIndex;
PDEVICE_OBJECT MyDeviceObject; 
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];

Status = NDIS_STATUS_SUCCESS;

//申请自旋锁 以到达资源共享的同步访问
NdisAllocateSpinLock(&GlobalLock);

//调用NdisMInitializeWrapper函数来保存在NdisWrapperHandle返回的句柄
NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);

do
{
//调用NdisMInitializeWrapper函数来保存在WrapperHandle返回的句柄
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);

//对于MiniportCharacteristics组件,如果驱动程序不用导出MiniportXxx这样的函数,则必须赋值为NULL
//如果要导出任何新版本的V4.0V5.0MiniportXxx函数,那么中间层驱动程序的主版本必须是V4.0,并且提供4.05.0版本的MiniportCharacteristics组件.
NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));

MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;
MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;

/***************************************************
下面开始注册中间层驱动程序的 MiniportXxx函数 
***************************************************/
MChars.HaltHandler = MPHalt;
MChars.InitializeHandler = MPInitialize;
MChars.QueryInformationHandler = MPQueryInformation;
MChars.SetInformationHandler = MPSetInformation;
MChars.ResetHandler = MPReset;

MChars.SendHandler = NULL;
MChars.SendPacketsHandler = MPSendPackets;

MChars.TransferDataHandler = MPTransferData;
MChars.ReturnPacketHandler = MPReturnPacket;
MChars.CheckForHangHandler = NULL;

#ifdef NDIS51_MINIPORT
MChars.CancelSendPacketsHandler = MPCancelSendPackets;
MChars.PnPEventNotifyHandler = MPDevicePnPEvent;
MChars.AdapterShutdownHandler = MPAdapterShutdown;
#endif // NDIS51_MINIPORT 


/*
传递上一步保存的句柄,并调用NdisIMRegisterLayeredMiniport函数来注册驱动程序的MiniportXxx系列函数。其中句柄NdisWrapperHandle是由先前的NdisMInitializeWrapper函数返回的。

当驱动程序调用NdisIMInitializeDeviceInstance函数,请求中间层驱动程序的MiniportInitialize函数对虚拟NIC进行初始化时,需要把句柄NdisWrapperHandle传入NDIS

当中间层驱动程序成功地绑定到一个或者多个NIC驱动程序上的时候或者是绑定到一个非NIC驱动程序上的时候也会调用NdisIMInitializeDeviceInstance函数。这样做使得中间层驱动程序可以初始化Miniport组件来接受虚拟NIC上的I/O请求
*/
Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle, &MChars, sizeof(MChars), &DriverHandle);

if (Status != NDIS_STATUS_SUCCESS)
{
break;
}

#ifndef WIN9X
NdisMRegisterUnloadHandler(NdisWrapperHandle, PtUnload);
#endif


//中间层驱动程序要做的事情:
//初始化NDIS_PROTOCOL_CHARACTERISTICS类型的结构. NDIS不再支持3.0版本的协议驱动.
//能够使用4.05.0版本的ProtocolCharacteristic结构体,协议驱动必须支持PNP即插即用功能.
NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;
PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;
NdisInitUnicodeString(&Name, L"Passthru"); 
PChars.Name = Name;

/******************************************************* 
下面开始注册中间层驱动程序的 ProtocolXxx函数 
这里主要是注册---下边界面向无连接的中间层驱动程序的ProtocolXxx函数 
*******************************************************/

PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
PChars.SendCompleteHandler = PtSendComplete;
PChars.TransferDataCompleteHandler = PtTransferDataComplete;

PChars.ResetCompleteHandler = PtResetComplete;
PChars.RequestCompleteHandler = PtRequestComplete;

PChars.ReceiveHandler = PtReceive;
PChars.ReceivePacketHandler = PtReceivePacket;
PChars.ReceiveCompleteHandler = PtReceiveComplete;

PChars.StatusHandler = PtStatus;
PChars.StatusCompleteHandler = PtStatusComplete;

PChars.BindAdapterHandler = PtBindAdapter;
PChars.UnbindAdapterHandler = PtUnbindAdapter;
PChars.UnloadHandler = PtUnloadProtocol;

PChars.PnPEventHandler= PtPNPHandler;


/*
如果驱动程序随后要绑定到底层的NDIS驱动程序上,则调用NdisRegisterProtocol函数来注册驱动程序的ProtocolXxx函数。
全局变量ProtHandle是在NDIS协议驱动里面的NdisRegisterProtocol函数里面初始化的,然后中间层驱动必须保存protHandle的值,并在将来NDIS中间层驱动程序的协议部分的函数调用中作为输入参数来传递.
*/

NdisRegisterProtocol(&Status, &ProtHandle,&PChars,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

if (Status != NDIS_STATUS_SUCCESS)
{
NdisIMDeregisterLayeredMiniport(DriverHandle);
break;
}

//如果驱动程序导出了MiniportXxxProtocolXxx这一些列的函数,那么就调用NdisIMAssociateMiniport函数向NDIS通告有关驱动程序的微端口低边界和协议高边界信息
NdisIMAssociateMiniport(DriverHandle, ProtHandle);
}
while (FALSE);

//----------------- 创建设备对象与符号连接----------------------------
RtlInitUnicodeString(&nameString, L"\\Device\\MyPassthru" ); 
RtlInitUnicodeString(&linkString, L"\\??\\MyPassthru"); 

for(FuncIndex = 0; 
FuncIndex <=IRP_MJ_MAXIMUM_FUNCTION; 
FuncIndex++)
{
MajorFunction[FuncIndex] = NULL;
}

MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
MajorFunction[IRP_MJ_DEVICE_CONTROL] = MydrvDispatchIoctl;


Status = NdisMRegisterDevice(
WrapperHandle, 
&nameString,
&linkString,
MajorFunction,
&MyDeviceObject,
&NdisDeviceHandle
);

if(Status != STATUS_SUCCESS)
{
DbgPrint("NdisMRegisterDevice failed!\n");
}



return(Status);
}


然后,我们就开始实现相应的回调函数。 然而为了收、发网络数据包,对它们进行控制,我们基本上只会去修改以下的回调函数:
下面我把相关的函数的功能给罗列出来。


/***************************************************************
MPSend函数的功能是发送单个数据包。 
若中间层驱动不支持MiniportSendPackets,那么MPSend函数必须实现。 

参数说明
MiniportAdapterContext 它是适配器。 
PacketArray 它是包描述符指针。 
Flags 它未被使用。 

***************************************************************/
NDIS_STATUS
MPSend(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet,
IN UINT Flags
)





/***************************************************************
MPSendPackets函数的功能是
用于指定网络上传输数据包的包描述符指针数组。该函数可以用来发送多个数据包。而不是只发送单个数据包。除非中间层驱动程序绑定到低层WAN NIC驱动程序上,并提供MiniportWanSend函数,否则驱动程序应提供对MPSendPackets函数的支持而不是对MPSend函数的支持。

参数说明:
MiniportAdapterContext 它是适配器。 
PacketArray 它是包描述符数组。 
NumberOfPackets 它是PacketArray的长度。 

每个数据包发送完成后无论是否成功都要调用 NdisMSendComplete函数。让上层的协议驱动能够收到SendCompleteHandler来判断数据包的完成状态。 
***************************************************************/
VOID
MPSendPackets(
IN NDIS_HANDLE MiniportAdapterContext,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)





/***************************************************************
MPTransferData函数的功能
该函数用于传输在前视缓冲区中没有指示的接收数据包的剩余部分。前视缓冲区由 
中间层驱动程序传递给 NdisMXxxIndicateReceive函数。这个被指示的数据包可以是 
中间层驱动程序的ProtocolReceive函数或者是ProtocolReceivePackets处理程序接收的 
转换数据包。 
如果中间层驱动程序通过调用NdisMXxxIndicateReceive函数向上层驱动程序指示接收 
数据包,那么MPTransferData函数必须提供。 

如果中间层通过调用驱动程序总是NdisMIndicateReceive函数向上层驱动程序指示接收 
数据包,那么MPTransferData函数可以不必提供。即 NdisMIndicateReceivePacket指示
接收数据包,那么传递给ProtocoltReceive函数 的前视缓冲区将总是获得完整的数据包。 
****************************************************************/
NDIS_STATUS
MPTransferData(
OUT PNDIS_PACKET Packet, //目的数据包
OUT PUINT BytesTransferred,//复制了多少数据
IN NDIS_HANDLE MiniportAdapterContext,//适配器结构体
IN NDIS_HANDLE MiniportReceiveContext,//上下文
IN UINT ByteOffset,//指向拷贝数据包的偏移
IN UINT BytesToTransfer//实际传输了多少字节的数据
)





/***************************************************************
PtTransferDataComplete函数的功能
它是MPTransferData()的异步完成函数。 
ProtocolReceive函数需要调用NdisTransferData函数,那么我们必须实现
PtTransferDataComplete的代码。

NdisTransferData调用之后,并且返回值是NDIS_STATUS_PENDING,在数据包传输完成了以后,会去调用PtTransferDataComplete函数用来表明一个数据包的传输完成。这时就会得到一个完整的数据包。 
**************************************************************/
VOID
PtTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)




/*************************************************************** 
PtReceive函数的功能是
该函数以指向包含网络接收数据的前视缓冲区的指针为参数被调用执行。如果这个前视缓冲区没有包含完整的网络数据包,那么ProtocolReceive函数将以包描述符作为参数,调用NdisTransferData函数。 
NdisTransferData调用之后,数据包传输完成了以后,会去调用
ProtocolTransferDataComplete函数以用来表明一个数据包的传输完成。这时就会得到一个完整的数据包。 


如果低层驱动程序调用了 NdisMIndicateReceivePacket指示接收数据包,那么传递给PtReceive函数的前视缓冲区将总是获得完整的数据包。 
如果中间层驱动不需要完整的数据包时,可以调用NdisMXxxIndicateReceice函数向上通知,这样就省略了获取完整数据包的过程。

前视缓冲区:考虑数据包的接收,如果我们只需要看见数据内容的前几个字节(TCP)就可以决定这个包是否是本协议所需要处理的,那么显然下层驱动就没有必要提交整个数据包,只提供一个包开始的几个字节就可以了。 

参数说明
ProtocolBindingContext 在绑定是得到的绑定句柄,即它是在NdisOpenAdapter被调用时设置的。 

MacReceiveContext 它指向一个不透明的环境变量,由底层NIC驱动传入,它用此句柄与从网络上收到的Packet关联。当调用NdisGetReceivePacket函数取得低层驱动上面的包描述符时,需要用到这个参数。当NDIS协议驱动的ProtocolReceive函数的实现中,可能要调用NdisTransferData函数,那么也会用到这个参数。 
HeaderBuffer 它是一个以太网帧,就是以太网的包头。它是个虚拟的地址,只能在当前函数中有效它不能被存储而作为全局变量来使用。 

HeaderBufferSize 它是包头的长度,它的值一般为14 
LookAheadBuffer 它是前视缓冲区指针。 
LookAheadBufferSize LookAheadBuffer的大小。 

PacketSize 它是完整的数据包长度(不包括包头)。 

PtReceive函数被调用了以后,系统将会去调用完成函数PtReceiveComplete 

如果传递给PtReceive的数据是通过NdisMXxxIndicateReceive进行指示的,那么传递给PtReceive的前视缓冲区的长度不会超过用OID_GEN_CURRENT_LOOKAHEAD调用NdisRequest返回的值。 

如果PtReceive的调用执行在NdisMIndicateReceivePacket之前进行,那么底层驱动程序把包数组中的一个或者多个包状态设置为 NDIS_STATUS_RESOURCES,那么前视缓冲区的大小总是等于整个网络数据包的大小。所以中间层驱动程序可以不必调用NdisTransferData函数。 
***************************************************************/

NDIS_STATUS
PtReceive(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)





/************************************************************** 
PtReceivePacket函数的功能是
这是一个可选函数。 如果中间层驱动程序所基于的NIC驱动程序指示的是数据包描述符指针数组,或者调用NdisMIndicateReceivePacket函数指示接收带外数据,那么驱动程序应该提供PtReceivePacket函数。 
如果开发者不能够确定中间层驱动程序的执行环境,也应该提供该函数,因为在能够产生多包指示的底层NIC驱动程序上,中间层驱动程序将获得更好的性能。 
**************************************************************/
INT
PtReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
)


我们可以在这几个回调函数里面来处理、过滤、分析 捕捉到的数据包。防火墙软件一般也都是在这几个回调函数里面进行编程。

其它的回调函数的代码,我们基本上不用去修改。

NDIS Passthru的例子很多,在网络上搜索一下,就有很多源代码例子,也有很多相关的技术说明。 



下面,我想重点的说明在Windows 7系统下,(当然是Win7 32/64位系统)如何做NDIS中间层驱动程序的开发,代码和之前老的Windows操作系统提供的Passthru例子的区别。





()在 Windows 7系统上进行开发

Win7系统下开发驱动程序,需要数字证书,还需要驱动签名认证。

由于Win7系统的内核做了大幅度的修改,它和XP系统的内核起了很大的变化,最显著的就是刚才说的:需要签名和证书。 还有就是:不能随意的HOOK SSDT了。


在开发NDIS驱动程序的时候,WDK开发包提供了一个新的框架,叫着NDIS Filter
NDIS Filter是一个例子工程。
假入我把WDK安装在E盘,那么这个工程代码就在:
E:\WinDDK\7600.16385.1\src\network\ndis\filter目录下。

把这个例子工程和原来的Passthru工程代码做比较,您会发现,原来需要导出来的2种类型的回调函数MiniportXXXProtocolXXX 在新的框架里面被全部隐藏起来了。
微软提供了新的函数。 一起来看看,微软提供了什么。
在这里,为了方便分析, 我把函数代码都做了功能注释,请大家一起看看。
代码如下:


#pragma NDIS_INIT_FUNCTION(DriverEntry)

#define LITTLE_ENDIAN (1)
//
// Global variables
// 
NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver
NDIS_HANDLE FilterDriverObject;
NDIS_HANDLE NdisFilterDeviceHandle = NULL;
PDEVICE_OBJECT DeviceObject = NULL;

FILTER_LOCK FilterListLock;
LIST_ENTRY FilterModuleList;
PWCHAR InstanceStrings = NULL;

NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {
{ 0, 0, 0},
0,
FilterSendNetBufferLists,
FilterSendNetBufferListsComplete,
NULL,
FilterReceiveNetBufferLists,
FilterReturnNetBufferLists
}; 

typedef struct in_addr {
union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;


#pragma push(1)
typedef struct IP_HEADER
{

#if LITTLE_ENDIAN
unsigned char ip_hl:4; /* 头长度 */
unsigned char ip_v:4; /* 版本号 */
#else
unsigned char ip_v:4;
unsigned char ip_hl:4; 
#endif

unsigned char TOS; // 服务类型

unsigned short TotLen; // 封包总长度,即整个IP包的长度
unsigned short ID; // 封包标识,唯一标识发送的每一个数据报
unsigned short FlagOff; // 标志
unsigned char TTL; // 生存时间,就是TTL
unsigned char Protocol; // 协议,可能是TCPUDPICMP
unsigned short Checksum; // 校验和
struct in_addr iaSrc; // IP地址
struct in_addr iaDst; // 目的PI地址

}IP_HEADER, *PIP_HEADER;


typedef struct tcp_header
{
unsigned short src_port; //源端口号
unsigned short dst_port; //目的端口号
unsigned int seq_no; //序列号
unsigned int ack_no; //确认号
#if LITTLE_ENDIAN
unsigned char reserved_1:4; //保留6位中的4位首部长度
unsigned char thl:4; //tcp头部长度
unsigned char flag:6; //6位标志
unsigned char reseverd_2:2; //保留6位中的2
#else
unsigned char thl:4; //tcp头部长度
unsigned char reserved_1:4; //保留6位中的4位首部长度
unsigned char reseverd_2:2; //保留6位中的2
unsigned char flag:6; //6位标志 
#endif
unsigned short wnd_size; //16位窗口大小
unsigned short chk_sum; //16TCP检验和
unsigned short urgt_p; //16为紧急指针

}TCP_HEADER,*PTCP_HEADER;


typedef struct udp_header 
{
USHORT srcport; // 源端口
USHORT dstport; // 目的端口
USHORT total_len; // 包括UDP报头及UDP数据的长度(单位:字节)
USHORT chksum; // 校验和

}UDP_HEADER,*PUDP_HEADER;
#pragma push()


#define IP_OFFSET 0x0E

//IP 协议类型
#define PROT_ICMP 0x01 
#define PROT_TCP 0x06 
#define PROT_UDP 0x11 


USHORT UTIL_htons( USHORT hostshort )
{
PUCHAR pBuffer;
USHORT nResult;

nResult = 0;
pBuffer = (PUCHAR )&hostshort;

nResult = ( (pBuffer[ 0 ] << 8) & 0xFF00) | (pBuffer[ 1 ] & 0x00FF);

return( nResult );
}


/*UTIL_ntohs把网络字节顺序转换成主机字节顺序*/
USHORT UTIL_ntohs( USHORT netshort )
{
return( UTIL_htons( netshort ) );
}



NTSTATUS 
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NDIS_STATUS Status;
NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
NDIS_STRING ServiceName;
NDIS_STRING UniqueName;
NDIS_STRING FriendlyName;
BOOLEAN bFalse = FALSE;

UNREFERENCED_PARAMETER(RegistryPath);

DEBUGP(DL_TRACE,("===>DriverEntry...\n"));

RtlInitUnicodeString(&ServiceName, FILTER_SERVICE_NAME);
RtlInitUnicodeString(&FriendlyName, FILTER_FRIENDLY_NAME);
RtlInitUnicodeString(&UniqueName, FILTER_UNIQUE_NAME);
FilterDriverObject = DriverObject;

do
{
NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS)); 

/*
大多数的NDIS6.0数据结构中包含的对象头结构的成员,即NDIS_OBJECT_HEADER结构。
对象头有三个成员:类型,大小和修改。如果头信息是不正确的,那么调用NDIS6.0函数将失败。
*/
FChars.Header.Type = 
NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;

FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
FChars.MajorDriverVersion = 1;
FChars.MinorDriverVersion = 0;
FChars.Flags = 0;

FChars.FriendlyName = FriendlyName;
FChars.UniqueName = UniqueName;
FChars.ServiceName = ServiceName;


/******************************************************
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Mandatory例程
******************************************************/
FChars.AttachHandler = FilterAttach;
FChars.DetachHandler = FilterDetach;
FChars.RestartHandler = FilterRestart;
FChars.PauseHandler = FilterPause;


/************************************************************
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且不能在运行时变更的例程
*************************************************************/
FChars.SetOptionsHandler = FilterRegisterOptions;
FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
FChars.OidRequestHandler = FilterOidRequest;
FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
FChars.StatusHandler = FilterStatus;
FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
FChars.NetPnPEventHandler = FilterNetPnPEvent; 
FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;



/**************************************************************
DIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且能在运行时变更的例程。

下面这4个例程也被定义在NDIS_FILTER_PARTIAL_CHARACTERISTICS,这个结构指定的
例程可以在运行时的FilterSetModuleOptions例程中调用NdisSetOptionHandles来改变。
如果过滤驱动要在例程中修改自身的一个特性,那么必须提供FilterSetModuleOptions例程。
****************************************************************/
FChars.SendNetBufferListsHandler = FilterSendNetBufferLists; 
FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;

///
FChars.CancelOidRequestHandler = FilterCancelOidRequest; 

DriverObject->DriverUnload = FilterUnload;

FilterDriverHandle = NULL;

FILTER_INIT_LOCK(&FilterListLock);

InitializeListHead(&FilterModuleList);

// Filter驱动注册给NDIS
Status = NdisFRegisterFilterDriver(DriverObject,
(NDIS_HANDLE)FilterDriverObject,
&FChars, 
&FilterDriverHandle);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_WARN, ("MSFilter: Register filter driver failed.\n")); 
break;
}
//
// Initilize spin locks
//

Status = FilterRegisterDevice();

if (Status != NDIS_STATUS_SUCCESS)
{
NdisFDeregisterFilterDriver(FilterDriverHandle);
FILTER_FREE_LOCK(&FilterListLock);
DEBUGP(DL_WARN, ("MSFilter: Register device for the filter driver failed.\n")); 
break;
}



while(bFalse);


DEBUGP(DL_TRACE, ("<===DriverEntry, Status = %8x\n", Status));
return Status;

}




//过滤驱动注册可选服务
NDIS_STATUS
FilterRegisterOptions(
IN NDIS_HANDLE NdisFilterDriverHandle, //它指向了这个过滤驱动
IN NDIS_HANDLE FilterDriverContext //它是这个驱动的上下文
)
{
DEBUGP(DL_TRACE, ("===>FilterRegisterOptions\n"));

ASSERT(NdisFilterDriverHandle == FilterDriverHandle);
ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);

if ((NdisFilterDriverHandle != (NDIS_HANDLE)FilterDriverHandle) ||
(FilterDriverContext != (NDIS_HANDLE)FilterDriverObject))
{
return NDIS_STATUS_INVALID_PARAMETER;
}

DEBUGP(DL_TRACE, ("<===FilterRegisterOptions\n"));

return (NDIS_STATUS_SUCCESS);
}



/*************************************************************** 
FilterAttach函数的功能:
Attaching状态表示:一个Filter Driver正准备附加一个Filter Module到一个驱动栈上。
一个过滤驱动进入Attaching状态下不能进行发送请求、接收指示、状态指示、OID请求操作。

当一个过滤驱动进入Attaching状态时,它可以:
(1)创建一个环境上下文区域并且初始化一个缓冲区池以及其Filter Module特点的资源。
(2)NDIS 传来给Filter AttachNdisFilterHandle作为输入来调用NdisFSetAttributes例程。


Attach is complete
Filter ModuleAttaching状态下并且Filter Driver初始化了所有的Filter Module所需要的
所有资源时,Filter Module进入Paused状态。


参数说明:
NdisFilterHandle 它用于所有过滤驱动中对Ndisxxx类例程的调用时引用指示这个过滤模块。
FilterDriverContext 它由NdisFRegisterFilterDriverFilterDriverContext来指定。
AttachParameters 它是过滤模块的初始化参数结构体。
**************************************************************/
NDIS_STATUS
FilterAttach(
IN NDIS_HANDLE NdisFilterHandle,
IN NDIS_HANDLE FilterDriverContext,
IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
)

{
PMS_FILTER pFilter = NULL;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_FILTER_ATTRIBUTES FilterAttributes;
ULONG Size;
BOOLEAN bFalse = FALSE;

DEBUGP(DL_TRACE, ("===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle));

do
{
ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);
if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject)
{
Status = NDIS_STATUS_INVALID_PARAMETER;
break;
}

if ((AttachParameters->MiniportMediaType != NdisMedium802_3)
&& (AttachParameters->MiniportMediaType != NdisMediumWan))
{
DEBUGP(DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3.\n")); 

Status = NDIS_STATUS_INVALID_PARAMETER;
break;
}

Size = sizeof(MS_FILTER) + 
AttachParameters->FilterModuleGuidName->Length + 
AttachParameters->BaseMiniportInstanceName->Length + 
AttachParameters->BaseMiniportName->Length;

pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size);
if (pFilter == NULL)
{
DEBUGP(DL_WARN, ("MSFilter: Failed to allocate context structure.\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}

NdisZeroMemory(pFilter, sizeof(MS_FILTER));

pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length;
pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER));

NdisMoveMemory(pFilter->FilterModuleName.Buffer, 
AttachParameters->FilterModuleGuidName->Buffer,
pFilter->FilterModuleName.Length);


pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length;
pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length);

NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer, 
AttachParameters->BaseMiniportInstanceName->Buffer,
pFilter->MiniportFriendlyName.Length);


pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length;
pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer + 
pFilter->MiniportFriendlyName.Length);
NdisMoveMemory(pFilter->MiniportName.Buffer, 
AttachParameters->BaseMiniportName->Buffer,
pFilter->MiniportName.Length);

pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex;

pFilter->TrackReceives = TRUE;
pFilter->TrackSends = TRUE;
pFilter->FilterHandle = NdisFilterHandle;


NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
FilterAttributes.Flags = 0;


Status = NdisFSetAttributes(NdisFilterHandle, 
pFilter, //pFilter参数的功能是,为过滤模块指定环境上下文
&FilterAttributes);

if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_WARN, ("MSFilter: Failed to set attributes.\n"));
break;
}

pFilter->State = FilterPaused;

FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink);
FILTER_RELEASE_LOCK(&FilterListLock, bFalse);

}
while (bFalse);

if (Status != NDIS_STATUS_SUCCESS)
{
if (pFilter != NULL)
{
FILTER_FREE_MEM(pFilter);
}
}

DEBUGP(DL_TRACE, ("<===FilterAttach: Status %x\n", Status));
return Status;
}




/************************************************************** 
FilterPause函数的功能:
Paused状态:在这种状态下,Filter Driver不能执行接收和发送操作。
FilterDriver执行FilterPause全程时它就进入了Pausing状态。

Pausing状态:在这种状态下,Filter Driver要为一个Filter Module完成停止发送和接收
处理所需要的所有准备工作。

一个在Pausing状态的Filter Driver有如下的约束:

(1)Filter Module不能发起任何新的接收指示,但可以传递下层驱动的接收指示。
(2)如果有Filter Module发起的接收指示还没有完成,那么必须等到它们全部完成。有只当
FilterReturnNetBufferLists完成所有外部接收指示后,暂停操作才能完成。
(3)要返回任何未处理的由下层驱动引发的接收指示给NDIS,只有等到NdisFReturnNetBufferLists返回了所有未处理的接收指示后暂停操作才能完成。这里也可以排队缓冲这些未完成的接收指示。
(4)立即用NdisFReturnNetBufferLists返回所有下层驱动新传来的接收指示,如果需要可以在返回之前制和排队这些接收指示。
(5)不能发起任何新的发送请求。
(6)如果有Filter Driver引的但NDIS还未完成的发送操作,必须等待它们完成。
(7)应该在FilterSendNetBufferLists例程中立即调用NdisFSendNetBufferListsComplete返回那些新达到的发送请求。并且为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。
(8)这时可以使用NdisFIndicateStatus提供状态指示。
(9)可以在FilterStatus中处理状态指示。
(10)可以在FilterOidRequest里面处理OID请求。
(11)可以发起一个OID操作。
(12)不能释放分配的相关资源,Filter Module相关的资源最好放在FilterDetach例程里面来释放。
(13)如果有用于发送和接收的定时器那么要停止它。

当成功停止发送和接收操作后就必须完成暂停操作。暂停操作的完成可以是同步的也可以是异步的。
若返回值是NDIS_STATUS_SUCCESS则,是同步。
若是异步,则返回NDIS_STATUS_PENDING。那么还必须调用NdisFPauseComplete函数。

暂停操作完成了以后,Filter Module进入了Paused状态。这里它有如下的约束:

(1)不能发起任何接收指示,但可以传递底层驱动发来的接收指示。
(2)需要立即调用NdisFReturnNetBufferLists返回底层驱动的接收指示给NDIS,如果需要可以在返回之前复制和排队这些接收指示。
(3)不能引发任何新的发送指示。
(4)需要立即调用NdisFSendNetBufferListsComplete完成那些在FilterSendNetBufferLists中收到的发送请求,并为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。
(5)这时可以使用NdisFIndicateStatus发起状态指示。
(6)可以在FilterStatus中进行状态指示处理。
(7)可以在FilterOidRequest里面处理OID请求。
(8)可以发起一个OID请求。


Filter Module进行Pausing状态时NDIS不会发起其它PnP操作,比如:附加、分离、重启。只有当Filter Module进入了Paused状态后NDIS才能对它进行分离和重启操作。
***************************************************************/
NDIS_STATUS
FilterPause(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
)

{
PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext);
NDIS_STATUS Status;
BOOLEAN bFalse = FALSE;

UNREFERENCED_PARAMETER(PauseParameters);

DEBUGP(DL_TRACE, ("===>NDISLWF FilterPause: FilterInstance %p\n", FilterModuleContext));


FILTER_ASSERT(pFilter->State == FilterRunning); 

FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
pFilter->State = FilterPausing;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);


Status = NDIS_STATUS_SUCCESS; 

pFilter->State = FilterPaused;

DEBUGP(DL_TRACE, ("<===FilterPause: Status %x\n", Status));
return Status;
}




/***************************************************************
FilterRestart函数的功能:
Restarting状态下,一个Filter Driver必须为一个Filter Module完成重启发送和接收数据时
所需要的所有准备工作。

Restart is complete
Filter ModuleRestarting状态下并且完成所有发送和接收所需要的准备工作时,Filter Module就进入了Running状态。

要启动一个Paused状态的Filter Module,如果有FilterSetModuleOptions就先调用它,接着调用FilterRestart

Filter ModuleRestarting状态下,它可以:
(1)完成任何正常的发送和接收所需要的准备工作。
(2)可读写Filter Module的配置参数。
(3)可以接收网络数据指示,拷贝和排队数据稍后只是给上层驱动或者丢弃数据。
(4)不能发起任何新的接收指示。
(5)应该立即调用NdisFSendNetBufferListsComplete例程来拒绝FilterSendNetBufferLists传来的发送的请求。应该设置每一个NET_BUFFER_LIST的完成状态为NDIS_STATUS_PAUSED
(6)可以使用NdisFIndicateStatus例程进行状态指示。
(7)可以控制OID请求操作。
(8)不能发起任何新的发送请求。
(9)应该调用NdisFReturnNetBufferLists返回所有新的接收指示。如果需要的话可以在接收指示返回之前拷贝它们。
(10)可以制作OID请求发送给下层驱动设置或查询配置信息。
(11)可以在FilterStatus中控制状态指示。
(12)返回时指示 NDIS_STATUS_SUCCESS 或失败状态,如果不Filter Module不能启动返回了失败,而它又是一个MandatoryFilter Driver 那个 NDIS将会结束这个驱动栈
在一个Filter Driver完成对发送和接收的重启后必须指示完成这个重启操作。 
Filter Driver的重启操作的完成可以是同步也可以是异步的,同步时返回 NDIS_STATUS_SUCCESS 异步时返回NDIS_STATUS_PENDING。如果返回的是 NDIS_STATUS_PENDING 就必须调用NdisFRestartComplete 例程在重启操作完成后。
在这种情况下,驱动需要传递给NdisFRestartComplete 一个固定状态(标识重启结果的成功或失败状态)

重启操作完成Filter Module就进入了 Running状态,恢得一切正常的发送和接收外理。
Filter DriverFilterRestart例程执行的时候NDIS不会发起任即插即用操作,如附加,分离,暂停请求等等。Ndis可以在Filter Module进入Running状态后发起一个暂停请求。
***************************************************************/
NDIS_STATUS
FilterRestart(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
)

{
NDIS_STATUS Status;
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; // BUGBUG, the cast may be wrong
NDIS_HANDLE ConfigurationHandle = NULL;


PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
NDIS_CONFIGURATION_OBJECT ConfigObject;

DEBUGP(DL_TRACE, ("===>FilterRestart: FilterModuleContext %p\n", FilterModuleContext));

FILTER_ASSERT(pFilter->State == FilterPaused);

ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
ConfigObject.NdisHandle = FilterDriverHandle;
ConfigObject.Flags = 0;

Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle);
if (Status != NDIS_STATUS_SUCCESS)


#if 0
//
// The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write 
// an event log.
//
PWCHAR ErrorString = L"Ndislwf";

DEBUGP(DL_WARN, ("FilterRestart: Cannot open configuration.\n"));
NdisWriteEventLogEntry(FilterDriverObject,
EVENT_NDIS_DRIVER_FAILURE,
0,
1,
&ErrorString,
sizeof(Status),
&Status);
#endif 

}


if (Status == NDIS_STATUS_SUCCESS)
{
NdisCloseConfiguration(ConfigurationHandle);
}

NdisRestartAttributes = RestartParameters->RestartAttributes;


if (NdisRestartAttributes != NULL)
{
PNDIS_RESTART_ATTRIBUTES NextAttributes;

ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);

NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;

NdisGeneralAttributes->LookaheadSize = 128;

NextAttributes = NdisRestartAttributes->Next;

while (NextAttributes != NULL)
{

NextAttributes = NextAttributes->Next;
}

}


pFilter->State = FilterRunning; 


Status = NDIS_STATUS_SUCCESS;

if (Status != NDIS_STATUS_SUCCESS)
{
pFilter->State = FilterPaused;
}


DEBUGP(DL_TRACE, ("<===FilterRestart: FilterModuleContext %p, Status %x\n", FilterModuleContext, Status));
return Status;
}



/************************************************************** 
FilterDetach函数的功能:
Detach状态:当Filter Driver从一个驱动栈上分离一个Filter Module,将发生该事件。
在驱动栈上分离一个过滤模块时,NDIS会暂停这个驱动栈。这意味着NDIS已经使过滤模块进入
Parse状态。即FilterPause函数先被调用了。

在这个例程中释放和这个过滤模块相关的环境上下文和其它资源。这个过程不能失败。
FilterDetach函数返回以后,NDIS会重新启动被暂停的驱动栈。

参数说明:
FilterDriverContext 它由NdisFRegisterFilterDriverFilterDriverContext来指定。
************************************************************/
VOID
FilterDetach(
IN NDIS_HANDLE FilterModuleContext
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN bFalse = FALSE;


DEBUGP(DL_TRACE, ("===>FilterDetach: FilterInstance %p\n", FilterModuleContext));


FILTER_ASSERT(pFilter->State == FilterPaused);


if (pFilter->FilterName.Buffer != NULL)
{
FILTER_FREE_MEM(pFilter->FilterName.Buffer);
}


FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
RemoveEntryList(&pFilter->FilterModuleLink);
FILTER_RELEASE_LOCK(&FilterListLock, bFalse);


FILTER_FREE_MEM(pFilter);


DEBUGP(DL_TRACE, ("<===FilterDetach Successfully\n"));

return;
}




/**************************************************************
系统只会在调用FilterDetach()分离了所有和本Filter Driver相关的Filter Module以后,才会调用FilterUnload例程。
****************************************************************/
VOID
FilterUnload(
IN PDRIVER_OBJECT DriverObject
)

{
#if DBG 
BOOLEAN bFalse = FALSE;
#endif

UNREFERENCED_PARAMETER(DriverObject);

DEBUGP(DL_TRACE, ("===>FilterUnload\n"));


FilterDeregisterDevice();
NdisFDeregisterFilterDriver(FilterDriverHandle);

#if DBG 
FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
ASSERT(IsListEmpty(&FilterModuleList));

FILTER_RELEASE_LOCK(&FilterListLock, bFalse);

#endif 

FILTER_FREE_LOCK(&FilterListLock);

DEBUGP(DL_TRACE, ("<===FilterUnload\n"));

return;

}



/***************************************************************
FilterOidRequest函数的功能:
Filter Module可以在Runnig状态、Restarting状态、Paused状态和Pauseing状态进行OID的控制和处理。
Filter Driver可以处理上层驱动引发的OID请求,NDIS调用Filter DriverFilterOidRequest例程来处理OID请求,Filter Driver需要调用NdisFOidRequest例程来转发请求给下层驱动。 

Filter Driver可以从FilterOidRequest同步和异步完成一个OID请求,分别返回NDIS_STATS_SUCCESSNDIS_STATUS_PENDING即可。FilterOidRequest可以用同步的直接完成一个OID请求并返回一个错误状态。 

如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用
NdisFOidRequestComplete来通知上层驱动求请求完成。在这种情况下,请求的结果通过
NdisFOidRequestCompleteOidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。


如果FilterOidRequest返回NDIS_STATUS_SUCCESS,通过FilterOidRequestOidRequest参数返回一个查询结果到上层。这时不调用 NdisFOidRequestComplete例程。 


要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest。如果一个OID请求不能被转发到下层驱动应该当立即返回。要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态或返回 NDIS_STATUS_PENDING 后调用NdisFOidRequestComplete。 


如果NdisFOidRequest返回NDIS_STATUS_PENDING,NDISOID请求完成后调用FilterOidRequestComplete来通知求请求完成在这种情况下,请求的结果通过NdisFOidRequestCompleteOidRequest参数返回给上层驱动,并通过 Status 参数返回请求完成的最终状态。


如果 NdisFOidRequest返回NDIS_STATUS_SUCCESS,通过NdisFOidRequestOidRequest参数返回一个查询结果到上层。这时不调用FilterOidRequestComplete例程。 
一个Filter Driver可以调用NdisFOidRequest引发OID请求在RestartingRunningPausingPaused 状态。 

注意:Filter Driver必须跟踪这个请求确保不在FilterOidRequestComplete中调用NdisFOidRequestComplete(因为请求是自己引发的不能传到上层)。 
****************************************************************/
NDIS_STATUS
FilterOidRequest(IN NDIS_HANDLE FilterModuleContext,IN PNDIS_OID_REQUEST Request)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_STATUS Status;
PNDIS_OID_REQUEST ClonedRequest=NULL;
BOOLEAN bSubmitted = FALSE;
PFILTER_REQUEST_CONTEXT Context;
BOOLEAN bFalse = FALSE;


DEBUGP(DL_TRACE, ("===>FilterOidRequest: Request %p.\n", Request));

do
{
Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle,
Request,
FILTER_TAG,
&ClonedRequest);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_WARN, ("FilerOidRequest: Cannot Clone Request\n"));
break;
}

Context = (PFILTER_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]);
*Context = Request;

bSubmitted = TRUE;


ClonedRequest->RequestId = Request->RequestId;

pFilter->PendingOidRequest = ClonedRequest;


//Filter Driver可以调用NdisFOidRequest引发一个OID查询和设置请求给下层驱动。
Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest);

if (Status != NDIS_STATUS_PENDING)
{

FilterOidRequestComplete(pFilter, ClonedRequest, Status);
Status = NDIS_STATUS_PENDING;



}while (bFalse);

if (bSubmitted == FALSE)
{
switch(Request->RequestType)
{
case NdisRequestMethod:
Request->DATA.METHOD_INFORMATION.BytesRead = 0;
Request->DATA.METHOD_INFORMATION.BytesNeeded = 0; 
Request->DATA.METHOD_INFORMATION.BytesWritten = 0; 
break;

case NdisRequestSetInformation:
Request->DATA.SET_INFORMATION.BytesRead = 0;
Request->DATA.SET_INFORMATION.BytesNeeded = 0; 
break;

case NdisRequestQueryInformation:
case NdisRequestQueryStatistics:
default:
Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
Request->DATA.QUERY_INFORMATION.BytesNeeded = 0; 
break;
}

}
DEBUGP(DL_TRACE, ("<===FilterOidRequest: Status %8x.\n", Status));

return Status;

}



/*************************************************************
FilterCancelOidRequest函数的功能:
NDIS调用FilterCancelOidRequest来取消一个OID请求,NDIS调用FilterCancelOidRequest,
Filter Driver应该尽可能快的调用NdisFCancelOidRequest。 
*************************************************************/
VOID
FilterCancelOidRequest(
IN NDIS_HANDLE FilterModuleContext,
IN PVOID RequestId
)
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNDIS_OID_REQUEST Request = NULL;
PFILTER_REQUEST_CONTEXT Context;
PNDIS_OID_REQUEST OriginalRequest = NULL;
BOOLEAN bFalse = FALSE;

FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);

Request = pFilter->PendingOidRequest;

if (Request != NULL)
{
Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);

OriginalRequest = (*Context);
}

if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId))
{
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);

NdisFCancelOidRequest(pFilter->FilterHandle, RequestId);
}
else
{
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
}


}


VOID
FilterOidRequestComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_OID_REQUEST Request,
IN NDIS_STATUS Status
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNDIS_OID_REQUEST OriginalRequest;
PFILTER_REQUEST_CONTEXT Context;
BOOLEAN bFalse = FALSE;

DEBUGP(DL_TRACE, ("===>FilterOidRequestComplete, Request %p.\n", Request));

Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);
OriginalRequest = (*Context);


if (OriginalRequest == NULL)
{
filterInternalRequestComplete(pFilter, Request, Status);
return;
}


FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);

ASSERT(pFilter->PendingOidRequest == Request);
pFilter->PendingOidRequest = NULL;

FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);

switch(Request->RequestType)
{
case NdisRequestMethod:
OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength = Request->DATA.METHOD_INFORMATION.OutputBufferLength;
OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead;
OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded; 
OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten; 
break;

case NdisRequestSetInformation: 
OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead;
OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded; 
break;

case NdisRequestQueryInformation:
case NdisRequestQueryStatistics:
default: 
OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten;
OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded;
break;
}


(*Context) = NULL;

NdisFreeCloneOidRequest(pFilter->FilterHandle, Request);


/*
如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用NdisFOidRequestComplete 来通知上层驱动求请求完成。在这种情况下,请求的结果通过NdisFOidRequestCompleteOidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。
要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest
如果一个OID请求不能被转发到下层驱动应该当立即返回。
要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态
或返回NDIS_STATUS_PENDING后调用NdisFOidRequestComplete。 
*/

NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status);

DEBUGP(DL_TRACE, ("<===FilterOidRequestComplete.\n"));
}




/*************************************************************
FilterStatus函数的功能:
当下层驱动报告状态的时候 NDIS会调用它。此外,Filter Driver还可以自己引发一个状态指示。

当下层驱动调用一个状态指示例程时(NdisMIndicateStatusExNdisFIndicateStats),NDIS
会调用Filter DriverFilterStatus例程。

Filter DriverFilterStatus中调用NdisFIndicateStatus传递一个状态指示给上层驱动。此外,还可以过滤状态指示(不用调用 NdisFIndicateStatus)或在调用 NdisFIndicateStatus之前修改状态信息。


Filter Driver要自己引发一个状态报告,可以在NDIS未调用 FilterStatus的情况下调用NdisFIndicateStatus。在这种情况下,Filter Driver要设置 SourceHandle 成员为 FilteAttech 参数提供的NdisFilterHandle句柄。
如果一个状态指示是一个OID请求相关的(下层请求一个 OID 下层要做相应的状态指示),那么状态的DestinationHandleRequestId成员要设置成上层的OID请求包携带的数据。 


Filter Driver调用NdisFIndicateStatusNDIS会调用相邻上层的状态指示函数(ProtocolStatusExFilterStatus)。 
****************************************************************/
VOID
FilterStatus(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_STATUS_INDICATION StatusIndication
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
#if DBG 
BOOLEAN bFalse = FALSE;
#endif

DEBUGP(DL_TRACE, ("===>FilterStaus, IndicateStatus = %8x.\n", StatusIndication->StatusCode));

#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
ASSERT(pFilter->bIndicating == FALSE);
pFilter->bIndicating = TRUE;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
#endif 


NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication);

#if DBG 
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
ASSERT(pFilter->bIndicating == TRUE);
pFilter->bIndicating = FALSE;

FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);


#endif

DEBUGP(DL_TRACE, ("<===FilterStaus.\n"));

}




/*
Filter Driver提供FilterPnpEventNotify来接收NDIS传递的PnP和电源管理事件
*/
VOID
FilterDevicePnPEventNotify(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent;
#if DBG
BOOLEAN bFalse = FALSE;
#endif

DEBUGP(DL_TRACE, ("===>FilterDevicePnPEventNotify: NetPnPEvent = %p.\n", NetDevicePnPEvent));

switch (DevicePnPEvent)
{

case NdisDevicePnPEventQueryRemoved: 
case NdisDevicePnPEventRemoved:
case NdisDevicePnPEventSurpriseRemoved:
case NdisDevicePnPEventQueryStopped:
case NdisDevicePnPEventStopped:
case NdisDevicePnPEventPowerProfileChanged:
case NdisDevicePnPEventFilterListChanged:

break;

default:
DEBUGP(DL_ERROR, ("FilterDevicePnPEventNotify: Invalid event.\n"));
FILTER_ASSERT(bFalse);

break;
}

//Filter Driver要下层驱动转发收到的事件,转发事件要用到NdisFDevicePnPEventNotify例程
NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent);

DEBUGP(DL_TRACE, ("<===FilterDevicePnPEventNotify\n"));

}





/*
Filter Driver提供了FilterNetPnpEvent例程来处理网络Pnp和电源管理事件通知。
*/
NDIS_STATUS
FilterNetPnPEvent(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
)
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

//Filter Driver需要转发网络PnP和电源管理事件给上层驱动。转发这些事件是通NdisFNetPnpEvent来完成的。 
Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification);

return Status;
}




/**************************************************************
FilterSendNetBufferListsComplete函数的功能:
NDIS调用 FilterSendNetBufferListsComplete 把发送的结构和数据返还给 Filter DriverNDIS可以收集多次NdisFSendNetBufferLists发送的结构和数据形成一个单链表传递给FilterSendNetBufferListsComplete。除非到NDIS调用FilterSendNetBufferListsComplete,否则一个发送请求的当前状态总是未知的。

一个过滤驱动是不能在NDIS调用FilterSendNetBufferListsComplete返回结构之前对NET_BUFFER_LIST和其关联的数据做检查的。FilterSendNetBufferListsComplete要完成一个发送请求完成后的任何必要的后继处理。当NDIS调用FilterSendNetBufferListsComplete,Filter Driver就重新获地对结构及结构相关资源的所有权。可以在 FilterSendNetBufferListsComplete中释放相关的资源和准备下一个NdisFSendNetBufferLists调用。 

NDIS总是按照过滤驱动调用NdisFSendNetBufferLists提交的顺序传递给下层驱动,但是回返FilterSendNetBufferListsComplete 的顺序则是任意的。Filter Driver可以请求一个回环发送请求,只要把NdisFSendNetBufferListsSendFlags设置成NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK就行了。NDIS会引发一个包含发送数据的接收包指示。


一个Filter Driver应该对自己引发的发送请求保持跟踪并确保在完成时不调用NdisFSendNetBufferComplete例程。 
**************************************************************/
VOID
FilterSendNetBufferListsComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
ULONG NumOfSendCompletes = 0;
BOOLEAN DispatchLevel;
PNET_BUFFER_LIST CurrNbl;

DEBUGP(DL_TRACE, ("===>SendNBLComplete, NetBufferList: %p.\n", NetBufferLists));


if (pFilter->TrackSends)
{
CurrNbl = NetBufferLists;
while (CurrNbl)
{
NumOfSendCompletes++;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);

}
DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingSends -= NumOfSendCompletes;
FILTER_LOG_SEND_REF(2, pFilter, PrevNbl, pFilter->OutstandingSends); 
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}

NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags);

DEBUGP(DL_TRACE, ("<===SendNBLComplete.\n"));
}




/*************************************************************
FilterSendNetBufferLists函数的功能:
NDIS调用一个Filter DriverFilterSendNetBufferLists例程来过滤上层驱动的发送请求。Filter Driver不能改变其它驱动传来的NET_BUFFER_LIST结构中的SourceHandle成员的值。它可以过滤数据并发送过滤的数据到下层驱动。
对每一个提交到FilterSendNetBufferListsNDIS_BUFFER_LIST,我们可做下面的操作。

1)可以把缓冲区通过 NdisFSendBufferLists 传递给下层驱动,NDIS 保证上下文空间对FilterDriver的有效性。过滤驱动可以在发送前修改缓冲区的内容。可以像处理自己引发的发送请求的缓冲区一样处理这个缓冲区。 
2)可以调用 NdisFSendNetBufferListsComplete 拒绝传递这个包 
3)排队缓冲区内容到本地的供以后处理。例如要在一定超时后处理或要接收到特定包后才处理等。如果支持这种处理方式就要支持取消请求的操作。 
4)可以拷贝缓冲区并引发一个发送请求。它类似自己引发一个发送请求,但必须先调用 NdisFSendNetBufferComplete返回上层驱动的缓冲区。

发送请求在驱动栈继续完成,当一个微端口驱动调用NdisMSendNetBufferListsComplete完成一个发送请求时,NDIS会调用微端口
驱动之上最近的Filter DriverFilterSendNetBufferLists例程。

在一个发送操作完成后,Filter Driver可以做在FilterSendNetBufferLists中所有修改的相反操作。FilterSendNetBufferListsComplete返回一个NET_BUFFER_LIST结构的单链表和发送请求的最终状态给上层的驱动。当最顶层的 Filter ModuleFilterSendNetBufferListsComplete被调用完成后NDIS会调用引发发送请求的协议驱动的ProtocolSendNetBufferListsComplete。如果Filter Driver不提供FilterSendNetBufferLists它还是可以引发一个发送操作的,但它必须提供一个FilterSendNetBufferListsComplete并且不能在这个例程里把这个事件传递给上层驱动。

一个Filter Driver可以传递或过滤一个上层驱动的回环请求,要传递一个回环请求,NDIS会设置FilterSendNetBufferListsSendFlags参数为NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK,Filter Driver在调用NdisFSendNetBufferLists时把这个标记传给它即可。在回环请求的情况下NDIS会指示一个包含发送数据的接收包。

通常情况下,如果一个Filter Driver修改的任何行为不是NDIS提供的标准服务,那么它应该当自己为NDIS提供相应的服务。例如,如果一个Filter Driver修改了一个硬件地址请求,就必须处理直接到这个新地址回环包。在这种情况下因为Filter Driver已经更改了地址NDIS是不能提供一个回环服务的。
还有就是如果Filter Driver设置了混杂模式那它就不能传递额外的数据给上层接收。 
**************************************************************/

VOID
FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags
)


{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNET_BUFFER_LIST CurrNbl;
BOOLEAN DispatchLevel;
BOOLEAN bFalse = FALSE;

DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists));

do
{

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);

#if DBG 

FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

CurrNbl = NetBufferLists;
while (CurrNbl)
{
NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
NdisFSendNetBufferListsComplete(pFilter->FilterHandle, 
NetBufferLists, 
DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
break;

}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

/******************************************************/

//在这里添加我们的代码

/******************************************************/

if (pFilter->TrackSends)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
CurrNbl = NetBufferLists;
while (CurrNbl)
{
pFilter->OutstandingSends++;
FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);

CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}


NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);


}
while (bFalse);

DEBUGP(DL_TRACE, ("<===SendNetBufferList. \n"));
}




/*************************************************************
FilterReturnNetBufferLists函数的功能:
如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists
返回指示数据。在这种情况下 Filter Driver失去了对NET_BUFFER_LIST的所有权,直到FilterReturnNetBufferLists被调用。

Filter Driver调用NdisFIndicateNetBufferLists 传递接收指示给驱动栈上的上层驱动,如果上层驱动保留了对缓冲区(NET_BUFFER_LIST)的所有权,NDIS会调用Filter DriverFilterReturnNetBufferLists 例程。

FilterReturnNetBufferLists中应该撤消在接收路径上(如在 FilterReciveNetBufferLists中做的一些处理)的操作。当最底层的Filter Module完成对缓冲区(NET_BUFFER_LIST)的处理后,NDIS把缓冲区返回给微端口驱动。如果FilterReceiveNetBufferListsReceiveFlags没有设置NDIS_RECEIVE_FLAGS_RESOURCES标记, FilterDriver调用NdisFReturnNetBufferList返回这个缓冲区数据,如果设置了FilterReceiveNetBufferLists直接返回时就把缓冲区返还给了下层微端口驱动。 
***************************************************************/
VOID
FilterReturnNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG ReturnFlags
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NULL;
UINT NumOfNetBufferLists = 0;
BOOLEAN DispatchLevel;
ULONG Ref;

DEBUGP(DL_TRACE, ("===>ReturnNetBufferLists, NetBufferLists is %p.\n", NetBufferLists));

if (pFilter->TrackReceives)
{
while (CurrNbl)
{

NumOfNetBufferLists ++;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
}
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);

if (pFilter->TrackReceives)
{
DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL(ReturnFlags);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

pFilter->OutstandingRcvs -= NumOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(3, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);



DEBUGP(DL_TRACE, ("<===ReturnNetBufferLists.\n"));


}



/***************************************************************
FilterReceiveNetBufferLists函数的功能:
Filter Driver调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。这个函数通过NET_BUFFER_LIST结构给上层驱动指示数据。Filter Driver可以从池中分配这个结构。如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为 NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists返回指示数据。在这种情况下Filter Driver失去了对NET_BUFFER_LIST的所有权直到FilterReturnNetBufferLists被调用。如果Filter Driver在调用NdisFIndicateReceiveNetBufferLists时设置ReceiveFlagsNDIS_RECEIVE_FLAGS_RESOURCES,在函数返回后Filter Driver会立即恢复对NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回,因为NDIS在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。 

注意一个Filter Driver应该跟踪自己引发的接收指示确保它在FilterReturnNetBufferLists
中不调用NdisFReturnNetBufferLists。 
***************************************************************/
VOID
FilterReceiveNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG NumberOfNetBufferLists,
IN ULONG ReceiveFlags
)

{

PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
ULONG Ref;
BOOLEAN bFalse = FALSE;


#if DBG
ULONG ReturnFlags;
#endif

DEBUGP(DL_TRACE, ("===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists));
do
{

DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))

ReturnFlags = 0;
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
{
NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
}

NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
}
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

ASSERT(NumberOfNetBufferLists >= 1);


/*--------------------------------------------------------------------------------------*/ 

//在这里添加我们的代码


/*---------------------------------------------------------------------------------------*/


if (pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs += NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;

FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}


/************************************************************
调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。

如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists 返回指示数据。

如果Filter Driver设置了NdisFIndicateReceiveNetBufferListsReceiveFlags值为
NDIS_RECEIVE_FLAGS_RESOURCES,那么在函数返回后Filter Driver会立即恢复对
NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回。
在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。
************************************************************/
NdisFIndicateReceiveNetBufferLists(
pFilter->FilterHandle,
NetBufferLists,
PortNumber, 
NumberOfNetBufferLists,
ReceiveFlags);


if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) && pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}

} while (bFalse);

DEBUGP(DL_TRACE, ("<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags));

}



/**************************************************************
FilterCancelSendNetBufferLists函数的功能:
过滤驱动调用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID宏为每一个NET_BUFFER_LIST标记一个取消Id
在为网络数据分配取消ID之前,必须先调用NdisGenratePartialCanceId获得取消ID的高字节。
这是为了确保不是驱动不会把一个取消ID分配给两个驱动驱动通常在DriverEntry调用
NdisGenratePartialCanceld,但是驱动可以在不同的时间多次调用它来获得多个取消ID
要取消被标记过取消ID且正在传输的数据,驱动可以调用NdisFCancelSendNetBufferLists例程
来完成。要获得取消ID可以用NDIS_GET_NET_BUFFER_LIST_CANCEL_ID宏来完成。

如果一个Filter Driver对所有发送的NET_BUFFER_LIST标记了相同的取消ID那它可以用一个 
NdisFCancelSendNetBufferLists来取消所有的发送请求。如果把一部发送请求的NET_BUFFER_LIST标记相同的取消ID那么就可以调用一次NdisFCancelSendNetBufferLists来取消这部分发送请求。

在实现这个功能时NDIS会调用下层驱动的取消发送功能。中断正在执行的发送任务后,下层驱动会
调用发送完成全程(:NdisMSendNetBufferListComplete)返回指定的NET_BUFFER_LIST结构并指定 返回状态为 NDIS_STATUS_CANCELLED, NDIS依次调用Filter DriverFilterSendNetBufferListsComplete例程。在FilterSendNetBufferListsComplete中要用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID设置取消的NET_BUFFER_LIST 
的取消ID 为 NULL,这样是为了防止这个ID,在 NET_BUFFER_LIST被再次分配时使用。 


上层驱动在取消一个未完成的发送请求时也必须对这个发送请求的 NET_BUFFER_LIST结构设定取消ID
NDIS会传递给Filter DriverFilterCancelSendNetBufferLists一个取消ID来取消发送请求的
NET_BUFFER_LIST发送。FilterCanCelSendNetBufferLists下执行下列操作。 
1)遍历 Filter Driver的发送队列,用 NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID获得队列中NET_BUFFER_LIST的取消IDFilterCancelSendBufferLists的取消ID比较。 
2)移除队列中取消 ID 和 FilterCancelSentBufferLists中取消ID相同的元素。 
3)调用 NdisFSendNetBufferListsComplete来完成这些NET_BUFFER_LIST并设定返回状
态为NDIS_STATUS_CANCELLED。 
4)调用NdisFCancelSendNetBufferLists传递取消发送请求给下层驱动。传递取消ID给下层驱动就Filter Driver取消自己引发的发关请求一样。 
*************************************************************/
VOID
FilterCancelSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PVOID CancelId
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;

NdisFCancelSendNetBufferLists(pFilter->FilterHandle,CancelId);
}




/**************************************************************
FilterSetModuleOptions函数的功能:
必须要在初始化时为驱动注册FilterSetModuleOptions例程,驱动可以在这个例程中初始化
NDIS_FILTER_PARTIAL_CHARACTERISTICS结构来调用NdisSetOptionalHandlers来完成必变。
这个例程如果存在那么在调用Filter DriverFilterRestart例程之前调用它。
***************************************************************/ 
NDIS_STATUS
FilterSetModuleOptions(
IN NDIS_HANDLE FilterModuleContext
)
{

PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
BOOLEAN bFalse = FALSE;


if (bFalse)
{
UINT i;


pFilter->CallsRestart++;

i = pFilter->CallsRestart % 8;

pFilter->TrackReceives = TRUE;
pFilter->TrackSends = TRUE;

NdisMoveMemory(&OptionalHandlers, &DefaultChars, sizeof(OptionalHandlers));
OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;
OptionalHandlers.Header.Size = sizeof(OptionalHandlers);
switch (i)
{

case 0: 
OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
pFilter->TrackReceives = FALSE;
break;

case 1:

OptionalHandlers.ReturnNetBufferListsHandler = NULL;
pFilter->TrackReceives = FALSE;
break;

case 2:
OptionalHandlers.SendNetBufferListsHandler = NULL;
pFilter->TrackSends = FALSE;
break;

case 3:
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
pFilter->TrackSends = FALSE;
break;

case 4:
OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
OptionalHandlers.ReturnNetBufferListsHandler = NULL;
break;

case 5:
OptionalHandlers.SendNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
break;

case 6:

OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
OptionalHandlers.ReturnNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
break;

case 7:
break;
}
Status = NdisSetOptionalHandlers(pFilter->FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&OptionalHandlers );
}
return Status;
}



NDIS_STATUS
filterDoInternalRequest(
IN PMS_FILTER FilterModuleContext,
IN NDIS_REQUEST_TYPE RequestType,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
IN ULONG OutputBufferLength, OPTIONAL
IN ULONG MethodId, OPTIONAL
OUT PULONG pBytesProcessed
)

{
FILTER_REQUEST FilterRequest;
PNDIS_OID_REQUEST NdisRequest = &FilterRequest.Request;
NDIS_STATUS Status;
BOOLEAN bFalse;


bFalse = FALSE;
NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));

NdisInitializeEvent(&FilterRequest.ReqEvent);

NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
NdisRequest->RequestType = RequestType;

switch (RequestType)
{
case NdisRequestQueryInformation:
NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =InformationBuffer;

NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;

break;

case NdisRequestSetInformation:
NdisRequest->DATA.SET_INFORMATION.Oid = Oid;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =InformationBuffer;

NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =InformationBufferLength;

break;

case NdisRequestMethod:
NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;
NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer = InformationBuffer;

NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength = InformationBufferLength;

NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
break;



default:
FILTER_ASSERT(bFalse);
break;
}

NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;

Status = NdisFOidRequest(FilterModuleContext->FilterHandle,NdisRequest);


if (Status == NDIS_STATUS_PENDING)
{

NdisWaitEvent(&FilterRequest.ReqEvent, 0);
Status = FilterRequest.Status;
}


if (Status == NDIS_STATUS_SUCCESS)
{
if (RequestType == NdisRequestSetInformation)
{
*pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;
}

if (RequestType == NdisRequestQueryInformation)
{
*pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
}

if (RequestType == NdisRequestMethod)
{
*pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;
}

if (RequestType == NdisRequestMethod)
{
if (*pBytesProcessed > OutputBufferLength)
{
*pBytesProcessed = OutputBufferLength;
}
}
else
{

if (*pBytesProcessed > InformationBufferLength)
{
*pBytesProcessed = InformationBufferLength;
}
}
}


return (Status);
}



VOID
filterInternalRequestComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_OID_REQUEST NdisRequest,
IN NDIS_STATUS Status
)


{
PFILTER_REQUEST FilterRequest;

UNREFERENCED_PARAMETER(FilterModuleContext);

FilterRequest = CONTAINING_RECORD(NdisRequest, FILTER_REQUEST, Request);

FilterRequest->Status = Status;

NdisSetEvent(&FilterRequest->ReqEvent);
}

网络数据由在网络上发送和接收的数据包组成。 NDIS 提供了数据结构来描述它们, NDIS 
6.0 提供了如下数据结构: 
1) NET_BUFFER 
2) NET_BUFFER LIST 
3) NET_BUFFER_LIST_CONTEXT

在 NDIS 6.0 中,NET_BUFFER 是封闭网络数据的基本构建块。每一个 NET_BUFFER 都有
一个 MDL 链。这些 MDL映射的缓冲区地址是 NET_BUFFER 指定的数据空间。这种数据映射
同 NDIS 5.X 及之前的版本使用的 NDIS_PACKET 中的映射是一样的。NDIS 提供函数来管理这
些 MDL 链。 
多个NET_BUFFER可以被附加到(可以被串到)一个NET_BUFFER_LIS上。这些NET_BUFFER
被组织成一个以 NULL 结束的单链表。驱动或 NDIS仅创建一个 NET_BUFFER_LIST,应该修改
它的链表给它插入或删除一些 NET_BUFFER 结构。 
NET_BUFFER_LIST 结构中包含的信息中描述了所有被串到一个链表上的 NET_BUFFER 
构。如果 NET_BUFFER_LIST 需要上下文信息,可以分配额外的空间来存储一个
NET_BUFFER_LIST_CONTEXT 结构。NDIS 提供函数来分配、访问 NET_BUFFER_LIST_CONTEXT
中的数据。 
多个 NET_BUFFER_LIST 结构可以串成一个 NET_BUFFER_LIST 链表。它们可以被组织成一
个以 NULL 结尾的单向链表。驱动可以对这个链表直接进行插入、删除操作。 
NDIS 6.0 中使用的 NET_BUFFER 结构相似于 NDIS 5.X 以前使用的 NDIS_PACKET结构,每
一个 NET_BUFFER 结构中都包装了一个网络数据包。

标 题: 【原创】NDIS中间层驱动开发在Win7系统下和Windows XP系统下的区别
作 者: tianhz
时 间: 2011-07-21,14:58:04
链 接: http://bbs.pediy.com/showthread.php?t=137545

NDIS中间层驱动的开发在Win7系统上和Windows XP系统上有差别。

我把NDIS中间层的讨论分成2块。 windows 7系统和Windows XP系统。

()在 Windows XP系统上进行开发
平时很多朋友包括我在内,我们都在XP系统上使用NDIS5.1的框架来进行程序开发。我们都使用
Microsoft WDK提供的 NDIS 的 Passthru例子,在这个例子上做进一步的修改,来达到我们的目地。

Passthru工程的 DriverEntry函数里面,我们都看见如下的代码:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NDIS_STATUS Status;
NDIS_PROTOCOL_CHARACTERISTICS PChars;
NDIS_MINIPORT_CHARACTERISTICS MChars;
PNDIS_CONFIGURATION_PARAMETER Param;
NDIS_STRING Name;
NDIS_HANDLE WrapperHandle;


UNICODE_STRING nameString, linkString; 
UINT FuncIndex;
PDEVICE_OBJECT MyDeviceObject; 
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];

Status = NDIS_STATUS_SUCCESS;

//申请自旋锁 以到达资源共享的同步访问
NdisAllocateSpinLock(&GlobalLock);

//调用NdisMInitializeWrapper函数来保存在NdisWrapperHandle返回的句柄
NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);

do
{
//调用NdisMInitializeWrapper函数来保存在WrapperHandle返回的句柄
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);

//对于MiniportCharacteristics组件,如果驱动程序不用导出MiniportXxx这样的函数,则必须赋值为NULL
//如果要导出任何新版本的V4.0V5.0MiniportXxx函数,那么中间层驱动程序的主版本必须是V4.0,并且提供4.05.0版本的MiniportCharacteristics组件.
NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));

MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;
MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;

/***************************************************
下面开始注册中间层驱动程序的 MiniportXxx函数 
***************************************************/
MChars.HaltHandler = MPHalt;
MChars.InitializeHandler = MPInitialize;
MChars.QueryInformationHandler = MPQueryInformation;
MChars.SetInformationHandler = MPSetInformation;
MChars.ResetHandler = MPReset;

MChars.SendHandler = NULL;
MChars.SendPacketsHandler = MPSendPackets;

MChars.TransferDataHandler = MPTransferData;
MChars.ReturnPacketHandler = MPReturnPacket;
MChars.CheckForHangHandler = NULL;

#ifdef NDIS51_MINIPORT
MChars.CancelSendPacketsHandler = MPCancelSendPackets;
MChars.PnPEventNotifyHandler = MPDevicePnPEvent;
MChars.AdapterShutdownHandler = MPAdapterShutdown;
#endif // NDIS51_MINIPORT 


/*
传递上一步保存的句柄,并调用NdisIMRegisterLayeredMiniport函数来注册驱动程序的MiniportXxx系列函数。其中句柄NdisWrapperHandle是由先前的NdisMInitializeWrapper函数返回的。

当驱动程序调用NdisIMInitializeDeviceInstance函数,请求中间层驱动程序的MiniportInitialize函数对虚拟NIC进行初始化时,需要把句柄NdisWrapperHandle传入NDIS

当中间层驱动程序成功地绑定到一个或者多个NIC驱动程序上的时候或者是绑定到一个非NIC驱动程序上的时候也会调用NdisIMInitializeDeviceInstance函数。这样做使得中间层驱动程序可以初始化Miniport组件来接受虚拟NIC上的I/O请求
*/
Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle, &MChars, sizeof(MChars), &DriverHandle);

if (Status != NDIS_STATUS_SUCCESS)
{
break;
}

#ifndef WIN9X
NdisMRegisterUnloadHandler(NdisWrapperHandle, PtUnload);
#endif


//中间层驱动程序要做的事情:
//初始化NDIS_PROTOCOL_CHARACTERISTICS类型的结构. NDIS不再支持3.0版本的协议驱动.
//能够使用4.05.0版本的ProtocolCharacteristic结构体,协议驱动必须支持PNP即插即用功能.
NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;
PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;
NdisInitUnicodeString(&Name, L"Passthru"); 
PChars.Name = Name;

/******************************************************* 
下面开始注册中间层驱动程序的 ProtocolXxx函数 
这里主要是注册---下边界面向无连接的中间层驱动程序的ProtocolXxx函数 
*******************************************************/

PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
PChars.SendCompleteHandler = PtSendComplete;
PChars.TransferDataCompleteHandler = PtTransferDataComplete;

PChars.ResetCompleteHandler = PtResetComplete;
PChars.RequestCompleteHandler = PtRequestComplete;

PChars.ReceiveHandler = PtReceive;
PChars.ReceivePacketHandler = PtReceivePacket;
PChars.ReceiveCompleteHandler = PtReceiveComplete;

PChars.StatusHandler = PtStatus;
PChars.StatusCompleteHandler = PtStatusComplete;

PChars.BindAdapterHandler = PtBindAdapter;
PChars.UnbindAdapterHandler = PtUnbindAdapter;
PChars.UnloadHandler = PtUnloadProtocol;

PChars.PnPEventHandler= PtPNPHandler;


/*
如果驱动程序随后要绑定到底层的NDIS驱动程序上,则调用NdisRegisterProtocol函数来注册驱动程序的ProtocolXxx函数。
全局变量ProtHandle是在NDIS协议驱动里面的NdisRegisterProtocol函数里面初始化的,然后中间层驱动必须保存protHandle的值,并在将来NDIS中间层驱动程序的协议部分的函数调用中作为输入参数来传递.
*/

NdisRegisterProtocol(&Status, &ProtHandle,&PChars,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

if (Status != NDIS_STATUS_SUCCESS)
{
NdisIMDeregisterLayeredMiniport(DriverHandle);
break;
}

//如果驱动程序导出了MiniportXxxProtocolXxx这一些列的函数,那么就调用NdisIMAssociateMiniport函数向NDIS通告有关驱动程序的微端口低边界和协议高边界信息
NdisIMAssociateMiniport(DriverHandle, ProtHandle);
}
while (FALSE);

//----------------- 创建设备对象与符号连接----------------------------
RtlInitUnicodeString(&nameString, L"\\Device\\MyPassthru" ); 
RtlInitUnicodeString(&linkString, L"\\??\\MyPassthru"); 

for(FuncIndex = 0; 
FuncIndex <=IRP_MJ_MAXIMUM_FUNCTION; 
FuncIndex++)
{
MajorFunction[FuncIndex] = NULL;
}

MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
MajorFunction[IRP_MJ_DEVICE_CONTROL] = MydrvDispatchIoctl;


Status = NdisMRegisterDevice(
WrapperHandle, 
&nameString,
&linkString,
MajorFunction,
&MyDeviceObject,
&NdisDeviceHandle
);

if(Status != STATUS_SUCCESS)
{
DbgPrint("NdisMRegisterDevice failed!\n");
}



return(Status);
}


然后,我们就开始实现相应的回调函数。 然而为了收、发网络数据包,对它们进行控制,我们基本上只会去修改以下的回调函数:
下面我把相关的函数的功能给罗列出来。


/***************************************************************
MPSend函数的功能是发送单个数据包。 
若中间层驱动不支持MiniportSendPackets,那么MPSend函数必须实现。 

参数说明
MiniportAdapterContext 它是适配器。 
PacketArray 它是包描述符指针。 
Flags 它未被使用。 

***************************************************************/
NDIS_STATUS
MPSend(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet,
IN UINT Flags
)





/***************************************************************
MPSendPackets函数的功能是
用于指定网络上传输数据包的包描述符指针数组。该函数可以用来发送多个数据包。而不是只发送单个数据包。除非中间层驱动程序绑定到低层WAN NIC驱动程序上,并提供MiniportWanSend函数,否则驱动程序应提供对MPSendPackets函数的支持而不是对MPSend函数的支持。

参数说明:
MiniportAdapterContext 它是适配器。 
PacketArray 它是包描述符数组。 
NumberOfPackets 它是PacketArray的长度。 

每个数据包发送完成后无论是否成功都要调用 NdisMSendComplete函数。让上层的协议驱动能够收到SendCompleteHandler来判断数据包的完成状态。 
***************************************************************/
VOID
MPSendPackets(
IN NDIS_HANDLE MiniportAdapterContext,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)





/***************************************************************
MPTransferData函数的功能
该函数用于传输在前视缓冲区中没有指示的接收数据包的剩余部分。前视缓冲区由 
中间层驱动程序传递给 NdisMXxxIndicateReceive函数。这个被指示的数据包可以是 
中间层驱动程序的ProtocolReceive函数或者是ProtocolReceivePackets处理程序接收的 
转换数据包。 
如果中间层驱动程序通过调用NdisMXxxIndicateReceive函数向上层驱动程序指示接收 
数据包,那么MPTransferData函数必须提供。 

如果中间层通过调用驱动程序总是NdisMIndicateReceive函数向上层驱动程序指示接收 
数据包,那么MPTransferData函数可以不必提供。即 NdisMIndicateReceivePacket指示
接收数据包,那么传递给ProtocoltReceive函数 的前视缓冲区将总是获得完整的数据包。 
****************************************************************/
NDIS_STATUS
MPTransferData(
OUT PNDIS_PACKET Packet, //目的数据包
OUT PUINT BytesTransferred,//复制了多少数据
IN NDIS_HANDLE MiniportAdapterContext,//适配器结构体
IN NDIS_HANDLE MiniportReceiveContext,//上下文
IN UINT ByteOffset,//指向拷贝数据包的偏移
IN UINT BytesToTransfer//实际传输了多少字节的数据
)





/***************************************************************
PtTransferDataComplete函数的功能
它是MPTransferData()的异步完成函数。 
ProtocolReceive函数需要调用NdisTransferData函数,那么我们必须实现
PtTransferDataComplete的代码。

NdisTransferData调用之后,并且返回值是NDIS_STATUS_PENDING,在数据包传输完成了以后,会去调用PtTransferDataComplete函数用来表明一个数据包的传输完成。这时就会得到一个完整的数据包。 
**************************************************************/
VOID
PtTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)




/*************************************************************** 
PtReceive函数的功能是
该函数以指向包含网络接收数据的前视缓冲区的指针为参数被调用执行。如果这个前视缓冲区没有包含完整的网络数据包,那么ProtocolReceive函数将以包描述符作为参数,调用NdisTransferData函数。 
NdisTransferData调用之后,数据包传输完成了以后,会去调用
ProtocolTransferDataComplete函数以用来表明一个数据包的传输完成。这时就会得到一个完整的数据包。 


如果低层驱动程序调用了 NdisMIndicateReceivePacket指示接收数据包,那么传递给PtReceive函数的前视缓冲区将总是获得完整的数据包。 
如果中间层驱动不需要完整的数据包时,可以调用NdisMXxxIndicateReceice函数向上通知,这样就省略了获取完整数据包的过程。

前视缓冲区:考虑数据包的接收,如果我们只需要看见数据内容的前几个字节(TCP)就可以决定这个包是否是本协议所需要处理的,那么显然下层驱动就没有必要提交整个数据包,只提供一个包开始的几个字节就可以了。 

参数说明
ProtocolBindingContext 在绑定是得到的绑定句柄,即它是在NdisOpenAdapter被调用时设置的。 

MacReceiveContext 它指向一个不透明的环境变量,由底层NIC驱动传入,它用此句柄与从网络上收到的Packet关联。当调用NdisGetReceivePacket函数取得低层驱动上面的包描述符时,需要用到这个参数。当NDIS协议驱动的ProtocolReceive函数的实现中,可能要调用NdisTransferData函数,那么也会用到这个参数。 
HeaderBuffer 它是一个以太网帧,就是以太网的包头。它是个虚拟的地址,只能在当前函数中有效它不能被存储而作为全局变量来使用。 

HeaderBufferSize 它是包头的长度,它的值一般为14 
LookAheadBuffer 它是前视缓冲区指针。 
LookAheadBufferSize LookAheadBuffer的大小。 

PacketSize 它是完整的数据包长度(不包括包头)。 

PtReceive函数被调用了以后,系统将会去调用完成函数PtReceiveComplete 

如果传递给PtReceive的数据是通过NdisMXxxIndicateReceive进行指示的,那么传递给PtReceive的前视缓冲区的长度不会超过用OID_GEN_CURRENT_LOOKAHEAD调用NdisRequest返回的值。 

如果PtReceive的调用执行在NdisMIndicateReceivePacket之前进行,那么底层驱动程序把包数组中的一个或者多个包状态设置为 NDIS_STATUS_RESOURCES,那么前视缓冲区的大小总是等于整个网络数据包的大小。所以中间层驱动程序可以不必调用NdisTransferData函数。 
***************************************************************/

NDIS_STATUS
PtReceive(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)





/************************************************************** 
PtReceivePacket函数的功能是
这是一个可选函数。 如果中间层驱动程序所基于的NIC驱动程序指示的是数据包描述符指针数组,或者调用NdisMIndicateReceivePacket函数指示接收带外数据,那么驱动程序应该提供PtReceivePacket函数。 
如果开发者不能够确定中间层驱动程序的执行环境,也应该提供该函数,因为在能够产生多包指示的底层NIC驱动程序上,中间层驱动程序将获得更好的性能。 
**************************************************************/
INT
PtReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
)


我们可以在这几个回调函数里面来处理、过滤、分析 捕捉到的数据包。防火墙软件一般也都是在这几个回调函数里面进行编程。

其它的回调函数的代码,我们基本上不用去修改。

NDIS Passthru的例子很多,在网络上搜索一下,就有很多源代码例子,也有很多相关的技术说明。 



下面,我想重点的说明在Windows 7系统下,(当然是Win7 32/64位系统)如何做NDIS中间层驱动程序的开发,代码和之前老的Windows操作系统提供的Passthru例子的区别。





()在 Windows 7系统上进行开发

Win7系统下开发驱动程序,需要数字证书,还需要驱动签名认证。

由于Win7系统的内核做了大幅度的修改,它和XP系统的内核起了很大的变化,最显著的就是刚才说的:需要签名和证书。 还有就是:不能随意的HOOK SSDT了。


在开发NDIS驱动程序的时候,WDK开发包提供了一个新的框架,叫着NDIS Filter
NDIS Filter是一个例子工程。
假入我把WDK安装在E盘,那么这个工程代码就在:
E:\WinDDK\7600.16385.1\src\network\ndis\filter目录下。

把这个例子工程和原来的Passthru工程代码做比较,您会发现,原来需要导出来的2种类型的回调函数MiniportXXXProtocolXXX 在新的框架里面被全部隐藏起来了。
微软提供了新的函数。 一起来看看,微软提供了什么。
在这里,为了方便分析, 我把函数代码都做了功能注释,请大家一起看看。
代码如下:


#pragma NDIS_INIT_FUNCTION(DriverEntry)

#define LITTLE_ENDIAN (1)
//
// Global variables
// 
NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver
NDIS_HANDLE FilterDriverObject;
NDIS_HANDLE NdisFilterDeviceHandle = NULL;
PDEVICE_OBJECT DeviceObject = NULL;

FILTER_LOCK FilterListLock;
LIST_ENTRY FilterModuleList;
PWCHAR InstanceStrings = NULL;

NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {
{ 0, 0, 0},
0,
FilterSendNetBufferLists,
FilterSendNetBufferListsComplete,
NULL,
FilterReceiveNetBufferLists,
FilterReturnNetBufferLists
}; 

typedef struct in_addr {
union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;


#pragma push(1)
typedef struct IP_HEADER
{

#if LITTLE_ENDIAN
unsigned char ip_hl:4; /* 头长度 */
unsigned char ip_v:4; /* 版本号 */
#else
unsigned char ip_v:4;
unsigned char ip_hl:4; 
#endif

unsigned char TOS; // 服务类型

unsigned short TotLen; // 封包总长度,即整个IP包的长度
unsigned short ID; // 封包标识,唯一标识发送的每一个数据报
unsigned short FlagOff; // 标志
unsigned char TTL; // 生存时间,就是TTL
unsigned char Protocol; // 协议,可能是TCPUDPICMP
unsigned short Checksum; // 校验和
struct in_addr iaSrc; // IP地址
struct in_addr iaDst; // 目的PI地址

}IP_HEADER, *PIP_HEADER;


typedef struct tcp_header
{
unsigned short src_port; //源端口号
unsigned short dst_port; //目的端口号
unsigned int seq_no; //序列号
unsigned int ack_no; //确认号
#if LITTLE_ENDIAN
unsigned char reserved_1:4; //保留6位中的4位首部长度
unsigned char thl:4; //tcp头部长度
unsigned char flag:6; //6位标志
unsigned char reseverd_2:2; //保留6位中的2
#else
unsigned char thl:4; //tcp头部长度
unsigned char reserved_1:4; //保留6位中的4位首部长度
unsigned char reseverd_2:2; //保留6位中的2
unsigned char flag:6; //6位标志 
#endif
unsigned short wnd_size; //16位窗口大小
unsigned short chk_sum; //16TCP检验和
unsigned short urgt_p; //16为紧急指针

}TCP_HEADER,*PTCP_HEADER;


typedef struct udp_header 
{
USHORT srcport; // 源端口
USHORT dstport; // 目的端口
USHORT total_len; // 包括UDP报头及UDP数据的长度(单位:字节)
USHORT chksum; // 校验和

}UDP_HEADER,*PUDP_HEADER;
#pragma push()


#define IP_OFFSET 0x0E

//IP 协议类型
#define PROT_ICMP 0x01 
#define PROT_TCP 0x06 
#define PROT_UDP 0x11 


USHORT UTIL_htons( USHORT hostshort )
{
PUCHAR pBuffer;
USHORT nResult;

nResult = 0;
pBuffer = (PUCHAR )&hostshort;

nResult = ( (pBuffer[ 0 ] << 8) & 0xFF00) | (pBuffer[ 1 ] & 0x00FF);

return( nResult );
}


/*UTIL_ntohs把网络字节顺序转换成主机字节顺序*/
USHORT UTIL_ntohs( USHORT netshort )
{
return( UTIL_htons( netshort ) );
}



NTSTATUS 
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NDIS_STATUS Status;
NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
NDIS_STRING ServiceName;
NDIS_STRING UniqueName;
NDIS_STRING FriendlyName;
BOOLEAN bFalse = FALSE;

UNREFERENCED_PARAMETER(RegistryPath);

DEBUGP(DL_TRACE,("===>DriverEntry...\n"));

RtlInitUnicodeString(&ServiceName, FILTER_SERVICE_NAME);
RtlInitUnicodeString(&FriendlyName, FILTER_FRIENDLY_NAME);
RtlInitUnicodeString(&UniqueName, FILTER_UNIQUE_NAME);
FilterDriverObject = DriverObject;

do
{
NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS)); 

/*
大多数的NDIS6.0数据结构中包含的对象头结构的成员,即NDIS_OBJECT_HEADER结构。
对象头有三个成员:类型,大小和修改。如果头信息是不正确的,那么调用NDIS6.0函数将失败。
*/
FChars.Header.Type = 
NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;

FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
FChars.MajorDriverVersion = 1;
FChars.MinorDriverVersion = 0;
FChars.Flags = 0;

FChars.FriendlyName = FriendlyName;
FChars.UniqueName = UniqueName;
FChars.ServiceName = ServiceName;


/******************************************************
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Mandatory例程
******************************************************/
FChars.AttachHandler = FilterAttach;
FChars.DetachHandler = FilterDetach;
FChars.RestartHandler = FilterRestart;
FChars.PauseHandler = FilterPause;


/************************************************************
NDIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且不能在运行时变更的例程
*************************************************************/
FChars.SetOptionsHandler = FilterRegisterOptions;
FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
FChars.OidRequestHandler = FilterOidRequest;
FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
FChars.StatusHandler = FilterStatus;
FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
FChars.NetPnPEventHandler = FilterNetPnPEvent; 
FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;



/**************************************************************
DIS_FILTER_DRIVER_CHARACTERISTICS结构中Optional且能在运行时变更的例程。

下面这4个例程也被定义在NDIS_FILTER_PARTIAL_CHARACTERISTICS,这个结构指定的
例程可以在运行时的FilterSetModuleOptions例程中调用NdisSetOptionHandles来改变。
如果过滤驱动要在例程中修改自身的一个特性,那么必须提供FilterSetModuleOptions例程。
****************************************************************/
FChars.SendNetBufferListsHandler = FilterSendNetBufferLists; 
FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;

///
FChars.CancelOidRequestHandler = FilterCancelOidRequest; 

DriverObject->DriverUnload = FilterUnload;

FilterDriverHandle = NULL;

FILTER_INIT_LOCK(&FilterListLock);

InitializeListHead(&FilterModuleList);

// Filter驱动注册给NDIS
Status = NdisFRegisterFilterDriver(DriverObject,
(NDIS_HANDLE)FilterDriverObject,
&FChars, 
&FilterDriverHandle);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_WARN, ("MSFilter: Register filter driver failed.\n")); 
break;
}
//
// Initilize spin locks
//

Status = FilterRegisterDevice();

if (Status != NDIS_STATUS_SUCCESS)
{
NdisFDeregisterFilterDriver(FilterDriverHandle);
FILTER_FREE_LOCK(&FilterListLock);
DEBUGP(DL_WARN, ("MSFilter: Register device for the filter driver failed.\n")); 
break;
}



while(bFalse);


DEBUGP(DL_TRACE, ("<===DriverEntry, Status = %8x\n", Status));
return Status;

}




//过滤驱动注册可选服务
NDIS_STATUS
FilterRegisterOptions(
IN NDIS_HANDLE NdisFilterDriverHandle, //它指向了这个过滤驱动
IN NDIS_HANDLE FilterDriverContext //它是这个驱动的上下文
)
{
DEBUGP(DL_TRACE, ("===>FilterRegisterOptions\n"));

ASSERT(NdisFilterDriverHandle == FilterDriverHandle);
ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);

if ((NdisFilterDriverHandle != (NDIS_HANDLE)FilterDriverHandle) ||
(FilterDriverContext != (NDIS_HANDLE)FilterDriverObject))
{
return NDIS_STATUS_INVALID_PARAMETER;
}

DEBUGP(DL_TRACE, ("<===FilterRegisterOptions\n"));

return (NDIS_STATUS_SUCCESS);
}



/*************************************************************** 
FilterAttach函数的功能:
Attaching状态表示:一个Filter Driver正准备附加一个Filter Module到一个驱动栈上。
一个过滤驱动进入Attaching状态下不能进行发送请求、接收指示、状态指示、OID请求操作。

当一个过滤驱动进入Attaching状态时,它可以:
(1)创建一个环境上下文区域并且初始化一个缓冲区池以及其Filter Module特点的资源。
(2)NDIS 传来给Filter AttachNdisFilterHandle作为输入来调用NdisFSetAttributes例程。


Attach is complete
Filter ModuleAttaching状态下并且Filter Driver初始化了所有的Filter Module所需要的
所有资源时,Filter Module进入Paused状态。


参数说明:
NdisFilterHandle 它用于所有过滤驱动中对Ndisxxx类例程的调用时引用指示这个过滤模块。
FilterDriverContext 它由NdisFRegisterFilterDriverFilterDriverContext来指定。
AttachParameters 它是过滤模块的初始化参数结构体。
**************************************************************/
NDIS_STATUS
FilterAttach(
IN NDIS_HANDLE NdisFilterHandle,
IN NDIS_HANDLE FilterDriverContext,
IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
)

{
PMS_FILTER pFilter = NULL;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_FILTER_ATTRIBUTES FilterAttributes;
ULONG Size;
BOOLEAN bFalse = FALSE;

DEBUGP(DL_TRACE, ("===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle));

do
{
ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);
if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject)
{
Status = NDIS_STATUS_INVALID_PARAMETER;
break;
}

if ((AttachParameters->MiniportMediaType != NdisMedium802_3)
&& (AttachParameters->MiniportMediaType != NdisMediumWan))
{
DEBUGP(DL_ERROR, ("MSFilter: Doesn't support media type other than NdisMedium802_3.\n")); 

Status = NDIS_STATUS_INVALID_PARAMETER;
break;
}

Size = sizeof(MS_FILTER) + 
AttachParameters->FilterModuleGuidName->Length + 
AttachParameters->BaseMiniportInstanceName->Length + 
AttachParameters->BaseMiniportName->Length;

pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size);
if (pFilter == NULL)
{
DEBUGP(DL_WARN, ("MSFilter: Failed to allocate context structure.\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}

NdisZeroMemory(pFilter, sizeof(MS_FILTER));

pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length;
pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER));

NdisMoveMemory(pFilter->FilterModuleName.Buffer, 
AttachParameters->FilterModuleGuidName->Buffer,
pFilter->FilterModuleName.Length);


pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length;
pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length);

NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer, 
AttachParameters->BaseMiniportInstanceName->Buffer,
pFilter->MiniportFriendlyName.Length);


pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length;
pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer + 
pFilter->MiniportFriendlyName.Length);
NdisMoveMemory(pFilter->MiniportName.Buffer, 
AttachParameters->BaseMiniportName->Buffer,
pFilter->MiniportName.Length);

pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex;

pFilter->TrackReceives = TRUE;
pFilter->TrackSends = TRUE;
pFilter->FilterHandle = NdisFilterHandle;


NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
FilterAttributes.Flags = 0;


Status = NdisFSetAttributes(NdisFilterHandle, 
pFilter, //pFilter参数的功能是,为过滤模块指定环境上下文
&FilterAttributes);

if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_WARN, ("MSFilter: Failed to set attributes.\n"));
break;
}

pFilter->State = FilterPaused;

FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink);
FILTER_RELEASE_LOCK(&FilterListLock, bFalse);

}
while (bFalse);

if (Status != NDIS_STATUS_SUCCESS)
{
if (pFilter != NULL)
{
FILTER_FREE_MEM(pFilter);
}
}

DEBUGP(DL_TRACE, ("<===FilterAttach: Status %x\n", Status));
return Status;
}




/************************************************************** 
FilterPause函数的功能:
Paused状态:在这种状态下,Filter Driver不能执行接收和发送操作。
FilterDriver执行FilterPause全程时它就进入了Pausing状态。

Pausing状态:在这种状态下,Filter Driver要为一个Filter Module完成停止发送和接收
处理所需要的所有准备工作。

一个在Pausing状态的Filter Driver有如下的约束:

(1)Filter Module不能发起任何新的接收指示,但可以传递下层驱动的接收指示。
(2)如果有Filter Module发起的接收指示还没有完成,那么必须等到它们全部完成。有只当
FilterReturnNetBufferLists完成所有外部接收指示后,暂停操作才能完成。
(3)要返回任何未处理的由下层驱动引发的接收指示给NDIS,只有等到NdisFReturnNetBufferLists返回了所有未处理的接收指示后暂停操作才能完成。这里也可以排队缓冲这些未完成的接收指示。
(4)立即用NdisFReturnNetBufferLists返回所有下层驱动新传来的接收指示,如果需要可以在返回之前制和排队这些接收指示。
(5)不能发起任何新的发送请求。
(6)如果有Filter Driver引的但NDIS还未完成的发送操作,必须等待它们完成。
(7)应该在FilterSendNetBufferLists例程中立即调用NdisFSendNetBufferListsComplete返回那些新达到的发送请求。并且为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。
(8)这时可以使用NdisFIndicateStatus提供状态指示。
(9)可以在FilterStatus中处理状态指示。
(10)可以在FilterOidRequest里面处理OID请求。
(11)可以发起一个OID操作。
(12)不能释放分配的相关资源,Filter Module相关的资源最好放在FilterDetach例程里面来释放。
(13)如果有用于发送和接收的定时器那么要停止它。

当成功停止发送和接收操作后就必须完成暂停操作。暂停操作的完成可以是同步的也可以是异步的。
若返回值是NDIS_STATUS_SUCCESS则,是同步。
若是异步,则返回NDIS_STATUS_PENDING。那么还必须调用NdisFPauseComplete函数。

暂停操作完成了以后,Filter Module进入了Paused状态。这里它有如下的约束:

(1)不能发起任何接收指示,但可以传递底层驱动发来的接收指示。
(2)需要立即调用NdisFReturnNetBufferLists返回底层驱动的接收指示给NDIS,如果需要可以在返回之前复制和排队这些接收指示。
(3)不能引发任何新的发送指示。
(4)需要立即调用NdisFSendNetBufferListsComplete完成那些在FilterSendNetBufferLists中收到的发送请求,并为每一个NET_BUFFER_LIST设置NDIS_STATUS_PAUSED返回状态。
(5)这时可以使用NdisFIndicateStatus发起状态指示。
(6)可以在FilterStatus中进行状态指示处理。
(7)可以在FilterOidRequest里面处理OID请求。
(8)可以发起一个OID请求。


Filter Module进行Pausing状态时NDIS不会发起其它PnP操作,比如:附加、分离、重启。只有当Filter Module进入了Paused状态后NDIS才能对它进行分离和重启操作。
***************************************************************/
NDIS_STATUS
FilterPause(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
)

{
PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext);
NDIS_STATUS Status;
BOOLEAN bFalse = FALSE;

UNREFERENCED_PARAMETER(PauseParameters);

DEBUGP(DL_TRACE, ("===>NDISLWF FilterPause: FilterInstance %p\n", FilterModuleContext));


FILTER_ASSERT(pFilter->State == FilterRunning); 

FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
pFilter->State = FilterPausing;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);


Status = NDIS_STATUS_SUCCESS; 

pFilter->State = FilterPaused;

DEBUGP(DL_TRACE, ("<===FilterPause: Status %x\n", Status));
return Status;
}




/***************************************************************
FilterRestart函数的功能:
Restarting状态下,一个Filter Driver必须为一个Filter Module完成重启发送和接收数据时
所需要的所有准备工作。

Restart is complete
Filter ModuleRestarting状态下并且完成所有发送和接收所需要的准备工作时,Filter Module就进入了Running状态。

要启动一个Paused状态的Filter Module,如果有FilterSetModuleOptions就先调用它,接着调用FilterRestart

Filter ModuleRestarting状态下,它可以:
(1)完成任何正常的发送和接收所需要的准备工作。
(2)可读写Filter Module的配置参数。
(3)可以接收网络数据指示,拷贝和排队数据稍后只是给上层驱动或者丢弃数据。
(4)不能发起任何新的接收指示。
(5)应该立即调用NdisFSendNetBufferListsComplete例程来拒绝FilterSendNetBufferLists传来的发送的请求。应该设置每一个NET_BUFFER_LIST的完成状态为NDIS_STATUS_PAUSED
(6)可以使用NdisFIndicateStatus例程进行状态指示。
(7)可以控制OID请求操作。
(8)不能发起任何新的发送请求。
(9)应该调用NdisFReturnNetBufferLists返回所有新的接收指示。如果需要的话可以在接收指示返回之前拷贝它们。
(10)可以制作OID请求发送给下层驱动设置或查询配置信息。
(11)可以在FilterStatus中控制状态指示。
(12)返回时指示 NDIS_STATUS_SUCCESS 或失败状态,如果不Filter Module不能启动返回了失败,而它又是一个MandatoryFilter Driver 那个 NDIS将会结束这个驱动栈
在一个Filter Driver完成对发送和接收的重启后必须指示完成这个重启操作。 
Filter Driver的重启操作的完成可以是同步也可以是异步的,同步时返回 NDIS_STATUS_SUCCESS 异步时返回NDIS_STATUS_PENDING。如果返回的是 NDIS_STATUS_PENDING 就必须调用NdisFRestartComplete 例程在重启操作完成后。
在这种情况下,驱动需要传递给NdisFRestartComplete 一个固定状态(标识重启结果的成功或失败状态)

重启操作完成Filter Module就进入了 Running状态,恢得一切正常的发送和接收外理。
Filter DriverFilterRestart例程执行的时候NDIS不会发起任即插即用操作,如附加,分离,暂停请求等等。Ndis可以在Filter Module进入Running状态后发起一个暂停请求。
***************************************************************/
NDIS_STATUS
FilterRestart(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
)

{
NDIS_STATUS Status;
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; // BUGBUG, the cast may be wrong
NDIS_HANDLE ConfigurationHandle = NULL;


PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
NDIS_CONFIGURATION_OBJECT ConfigObject;

DEBUGP(DL_TRACE, ("===>FilterRestart: FilterModuleContext %p\n", FilterModuleContext));

FILTER_ASSERT(pFilter->State == FilterPaused);

ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
ConfigObject.NdisHandle = FilterDriverHandle;
ConfigObject.Flags = 0;

Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle);
if (Status != NDIS_STATUS_SUCCESS)


#if 0
//
// The code is here just to demonstrate how to call NDIS to write an eventlog. If drivers need to write 
// an event log.
//
PWCHAR ErrorString = L"Ndislwf";

DEBUGP(DL_WARN, ("FilterRestart: Cannot open configuration.\n"));
NdisWriteEventLogEntry(FilterDriverObject,
EVENT_NDIS_DRIVER_FAILURE,
0,
1,
&ErrorString,
sizeof(Status),
&Status);
#endif 

}


if (Status == NDIS_STATUS_SUCCESS)
{
NdisCloseConfiguration(ConfigurationHandle);
}

NdisRestartAttributes = RestartParameters->RestartAttributes;


if (NdisRestartAttributes != NULL)
{
PNDIS_RESTART_ATTRIBUTES NextAttributes;

ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);

NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;

NdisGeneralAttributes->LookaheadSize = 128;

NextAttributes = NdisRestartAttributes->Next;

while (NextAttributes != NULL)
{

NextAttributes = NextAttributes->Next;
}

}


pFilter->State = FilterRunning; 


Status = NDIS_STATUS_SUCCESS;

if (Status != NDIS_STATUS_SUCCESS)
{
pFilter->State = FilterPaused;
}


DEBUGP(DL_TRACE, ("<===FilterRestart: FilterModuleContext %p, Status %x\n", FilterModuleContext, Status));
return Status;
}



/************************************************************** 
FilterDetach函数的功能:
Detach状态:当Filter Driver从一个驱动栈上分离一个Filter Module,将发生该事件。
在驱动栈上分离一个过滤模块时,NDIS会暂停这个驱动栈。这意味着NDIS已经使过滤模块进入
Parse状态。即FilterPause函数先被调用了。

在这个例程中释放和这个过滤模块相关的环境上下文和其它资源。这个过程不能失败。
FilterDetach函数返回以后,NDIS会重新启动被暂停的驱动栈。

参数说明:
FilterDriverContext 它由NdisFRegisterFilterDriverFilterDriverContext来指定。
************************************************************/
VOID
FilterDetach(
IN NDIS_HANDLE FilterModuleContext
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN bFalse = FALSE;


DEBUGP(DL_TRACE, ("===>FilterDetach: FilterInstance %p\n", FilterModuleContext));


FILTER_ASSERT(pFilter->State == FilterPaused);


if (pFilter->FilterName.Buffer != NULL)
{
FILTER_FREE_MEM(pFilter->FilterName.Buffer);
}


FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
RemoveEntryList(&pFilter->FilterModuleLink);
FILTER_RELEASE_LOCK(&FilterListLock, bFalse);


FILTER_FREE_MEM(pFilter);


DEBUGP(DL_TRACE, ("<===FilterDetach Successfully\n"));

return;
}




/**************************************************************
系统只会在调用FilterDetach()分离了所有和本Filter Driver相关的Filter Module以后,才会调用FilterUnload例程。
****************************************************************/
VOID
FilterUnload(
IN PDRIVER_OBJECT DriverObject
)

{
#if DBG 
BOOLEAN bFalse = FALSE;
#endif

UNREFERENCED_PARAMETER(DriverObject);

DEBUGP(DL_TRACE, ("===>FilterUnload\n"));


FilterDeregisterDevice();
NdisFDeregisterFilterDriver(FilterDriverHandle);

#if DBG 
FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
ASSERT(IsListEmpty(&FilterModuleList));

FILTER_RELEASE_LOCK(&FilterListLock, bFalse);

#endif 

FILTER_FREE_LOCK(&FilterListLock);

DEBUGP(DL_TRACE, ("<===FilterUnload\n"));

return;

}



/***************************************************************
FilterOidRequest函数的功能:
Filter Module可以在Runnig状态、Restarting状态、Paused状态和Pauseing状态进行OID的控制和处理。
Filter Driver可以处理上层驱动引发的OID请求,NDIS调用Filter DriverFilterOidRequest例程来处理OID请求,Filter Driver需要调用NdisFOidRequest例程来转发请求给下层驱动。 

Filter Driver可以从FilterOidRequest同步和异步完成一个OID请求,分别返回NDIS_STATS_SUCCESSNDIS_STATUS_PENDING即可。FilterOidRequest可以用同步的直接完成一个OID请求并返回一个错误状态。 

如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用
NdisFOidRequestComplete来通知上层驱动求请求完成。在这种情况下,请求的结果通过
NdisFOidRequestCompleteOidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。


如果FilterOidRequest返回NDIS_STATUS_SUCCESS,通过FilterOidRequestOidRequest参数返回一个查询结果到上层。这时不调用 NdisFOidRequestComplete例程。 


要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest。如果一个OID请求不能被转发到下层驱动应该当立即返回。要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态或返回 NDIS_STATUS_PENDING 后调用NdisFOidRequestComplete。 


如果NdisFOidRequest返回NDIS_STATUS_PENDING,NDISOID请求完成后调用FilterOidRequestComplete来通知求请求完成在这种情况下,请求的结果通过NdisFOidRequestCompleteOidRequest参数返回给上层驱动,并通过 Status 参数返回请求完成的最终状态。


如果 NdisFOidRequest返回NDIS_STATUS_SUCCESS,通过NdisFOidRequestOidRequest参数返回一个查询结果到上层。这时不调用FilterOidRequestComplete例程。 
一个Filter Driver可以调用NdisFOidRequest引发OID请求在RestartingRunningPausingPaused 状态。 

注意:Filter Driver必须跟踪这个请求确保不在FilterOidRequestComplete中调用NdisFOidRequestComplete(因为请求是自己引发的不能传到上层)。 
****************************************************************/
NDIS_STATUS
FilterOidRequest(IN NDIS_HANDLE FilterModuleContext,IN PNDIS_OID_REQUEST Request)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_STATUS Status;
PNDIS_OID_REQUEST ClonedRequest=NULL;
BOOLEAN bSubmitted = FALSE;
PFILTER_REQUEST_CONTEXT Context;
BOOLEAN bFalse = FALSE;


DEBUGP(DL_TRACE, ("===>FilterOidRequest: Request %p.\n", Request));

do
{
Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle,
Request,
FILTER_TAG,
&ClonedRequest);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_WARN, ("FilerOidRequest: Cannot Clone Request\n"));
break;
}

Context = (PFILTER_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]);
*Context = Request;

bSubmitted = TRUE;


ClonedRequest->RequestId = Request->RequestId;

pFilter->PendingOidRequest = ClonedRequest;


//Filter Driver可以调用NdisFOidRequest引发一个OID查询和设置请求给下层驱动。
Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest);

if (Status != NDIS_STATUS_PENDING)
{

FilterOidRequestComplete(pFilter, ClonedRequest, Status);
Status = NDIS_STATUS_PENDING;



}while (bFalse);

if (bSubmitted == FALSE)
{
switch(Request->RequestType)
{
case NdisRequestMethod:
Request->DATA.METHOD_INFORMATION.BytesRead = 0;
Request->DATA.METHOD_INFORMATION.BytesNeeded = 0; 
Request->DATA.METHOD_INFORMATION.BytesWritten = 0; 
break;

case NdisRequestSetInformation:
Request->DATA.SET_INFORMATION.BytesRead = 0;
Request->DATA.SET_INFORMATION.BytesNeeded = 0; 
break;

case NdisRequestQueryInformation:
case NdisRequestQueryStatistics:
default:
Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
Request->DATA.QUERY_INFORMATION.BytesNeeded = 0; 
break;
}

}
DEBUGP(DL_TRACE, ("<===FilterOidRequest: Status %8x.\n", Status));

return Status;

}



/*************************************************************
FilterCancelOidRequest函数的功能:
NDIS调用FilterCancelOidRequest来取消一个OID请求,NDIS调用FilterCancelOidRequest,
Filter Driver应该尽可能快的调用NdisFCancelOidRequest。 
*************************************************************/
VOID
FilterCancelOidRequest(
IN NDIS_HANDLE FilterModuleContext,
IN PVOID RequestId
)
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNDIS_OID_REQUEST Request = NULL;
PFILTER_REQUEST_CONTEXT Context;
PNDIS_OID_REQUEST OriginalRequest = NULL;
BOOLEAN bFalse = FALSE;

FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);

Request = pFilter->PendingOidRequest;

if (Request != NULL)
{
Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);

OriginalRequest = (*Context);
}

if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId))
{
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);

NdisFCancelOidRequest(pFilter->FilterHandle, RequestId);
}
else
{
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
}


}


VOID
FilterOidRequestComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_OID_REQUEST Request,
IN NDIS_STATUS Status
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNDIS_OID_REQUEST OriginalRequest;
PFILTER_REQUEST_CONTEXT Context;
BOOLEAN bFalse = FALSE;

DEBUGP(DL_TRACE, ("===>FilterOidRequestComplete, Request %p.\n", Request));

Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);
OriginalRequest = (*Context);


if (OriginalRequest == NULL)
{
filterInternalRequestComplete(pFilter, Request, Status);
return;
}


FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);

ASSERT(pFilter->PendingOidRequest == Request);
pFilter->PendingOidRequest = NULL;

FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);

switch(Request->RequestType)
{
case NdisRequestMethod:
OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength = Request->DATA.METHOD_INFORMATION.OutputBufferLength;
OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead;
OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded; 
OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten; 
break;

case NdisRequestSetInformation: 
OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead;
OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded; 
break;

case NdisRequestQueryInformation:
case NdisRequestQueryStatistics:
default: 
OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten;
OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded;
break;
}


(*Context) = NULL;

NdisFreeCloneOidRequest(pFilter->FilterHandle, Request);


/*
如果FilterOidRequest返回NDIS_STATUS_PENDING,就必须在OID请求完成后调用NdisFOidRequestComplete 来通知上层驱动求请求完成。在这种情况下,请求的结果通过NdisFOidRequestCompleteOidRequest参数返回给上层驱动,并通过Status参数返回请求完成的最终状态。
要转发OID请求到下层驱动,Filter Driver必须调用NdisFOidRequest
如果一个OID请求不能被转发到下层驱动应该当立即返回。
要完成一个请求且不转发可以直接返回NDIS_STATUS_SUCCESS或其它错误状态
或返回NDIS_STATUS_PENDING后调用NdisFOidRequestComplete。 
*/

NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status);

DEBUGP(DL_TRACE, ("<===FilterOidRequestComplete.\n"));
}




/*************************************************************
FilterStatus函数的功能:
当下层驱动报告状态的时候 NDIS会调用它。此外,Filter Driver还可以自己引发一个状态指示。

当下层驱动调用一个状态指示例程时(NdisMIndicateStatusExNdisFIndicateStats),NDIS
会调用Filter DriverFilterStatus例程。

Filter DriverFilterStatus中调用NdisFIndicateStatus传递一个状态指示给上层驱动。此外,还可以过滤状态指示(不用调用 NdisFIndicateStatus)或在调用 NdisFIndicateStatus之前修改状态信息。


Filter Driver要自己引发一个状态报告,可以在NDIS未调用 FilterStatus的情况下调用NdisFIndicateStatus。在这种情况下,Filter Driver要设置 SourceHandle 成员为 FilteAttech 参数提供的NdisFilterHandle句柄。
如果一个状态指示是一个OID请求相关的(下层请求一个 OID 下层要做相应的状态指示),那么状态的DestinationHandleRequestId成员要设置成上层的OID请求包携带的数据。 


Filter Driver调用NdisFIndicateStatusNDIS会调用相邻上层的状态指示函数(ProtocolStatusExFilterStatus)。 
****************************************************************/
VOID
FilterStatus(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_STATUS_INDICATION StatusIndication
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
#if DBG 
BOOLEAN bFalse = FALSE;
#endif

DEBUGP(DL_TRACE, ("===>FilterStaus, IndicateStatus = %8x.\n", StatusIndication->StatusCode));

#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
ASSERT(pFilter->bIndicating == FALSE);
pFilter->bIndicating = TRUE;
FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
#endif 


NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication);

#if DBG 
FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
ASSERT(pFilter->bIndicating == TRUE);
pFilter->bIndicating = FALSE;

FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);


#endif

DEBUGP(DL_TRACE, ("<===FilterStaus.\n"));

}




/*
Filter Driver提供FilterPnpEventNotify来接收NDIS传递的PnP和电源管理事件
*/
VOID
FilterDevicePnPEventNotify(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent;
#if DBG
BOOLEAN bFalse = FALSE;
#endif

DEBUGP(DL_TRACE, ("===>FilterDevicePnPEventNotify: NetPnPEvent = %p.\n", NetDevicePnPEvent));

switch (DevicePnPEvent)
{

case NdisDevicePnPEventQueryRemoved: 
case NdisDevicePnPEventRemoved:
case NdisDevicePnPEventSurpriseRemoved:
case NdisDevicePnPEventQueryStopped:
case NdisDevicePnPEventStopped:
case NdisDevicePnPEventPowerProfileChanged:
case NdisDevicePnPEventFilterListChanged:

break;

default:
DEBUGP(DL_ERROR, ("FilterDevicePnPEventNotify: Invalid event.\n"));
FILTER_ASSERT(bFalse);

break;
}

//Filter Driver要下层驱动转发收到的事件,转发事件要用到NdisFDevicePnPEventNotify例程
NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent);

DEBUGP(DL_TRACE, ("<===FilterDevicePnPEventNotify\n"));

}





/*
Filter Driver提供了FilterNetPnpEvent例程来处理网络Pnp和电源管理事件通知。
*/
NDIS_STATUS
FilterNetPnPEvent(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
)
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

//Filter Driver需要转发网络PnP和电源管理事件给上层驱动。转发这些事件是通NdisFNetPnpEvent来完成的。 
Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification);

return Status;
}




/**************************************************************
FilterSendNetBufferListsComplete函数的功能:
NDIS调用 FilterSendNetBufferListsComplete 把发送的结构和数据返还给 Filter DriverNDIS可以收集多次NdisFSendNetBufferLists发送的结构和数据形成一个单链表传递给FilterSendNetBufferListsComplete。除非到NDIS调用FilterSendNetBufferListsComplete,否则一个发送请求的当前状态总是未知的。

一个过滤驱动是不能在NDIS调用FilterSendNetBufferListsComplete返回结构之前对NET_BUFFER_LIST和其关联的数据做检查的。FilterSendNetBufferListsComplete要完成一个发送请求完成后的任何必要的后继处理。当NDIS调用FilterSendNetBufferListsComplete,Filter Driver就重新获地对结构及结构相关资源的所有权。可以在 FilterSendNetBufferListsComplete中释放相关的资源和准备下一个NdisFSendNetBufferLists调用。 

NDIS总是按照过滤驱动调用NdisFSendNetBufferLists提交的顺序传递给下层驱动,但是回返FilterSendNetBufferListsComplete 的顺序则是任意的。Filter Driver可以请求一个回环发送请求,只要把NdisFSendNetBufferListsSendFlags设置成NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK就行了。NDIS会引发一个包含发送数据的接收包指示。


一个Filter Driver应该对自己引发的发送请求保持跟踪并确保在完成时不调用NdisFSendNetBufferComplete例程。 
**************************************************************/
VOID
FilterSendNetBufferListsComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
ULONG NumOfSendCompletes = 0;
BOOLEAN DispatchLevel;
PNET_BUFFER_LIST CurrNbl;

DEBUGP(DL_TRACE, ("===>SendNBLComplete, NetBufferList: %p.\n", NetBufferLists));


if (pFilter->TrackSends)
{
CurrNbl = NetBufferLists;
while (CurrNbl)
{
NumOfSendCompletes++;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);

}
DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingSends -= NumOfSendCompletes;
FILTER_LOG_SEND_REF(2, pFilter, PrevNbl, pFilter->OutstandingSends); 
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}

NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags);

DEBUGP(DL_TRACE, ("<===SendNBLComplete.\n"));
}




/*************************************************************
FilterSendNetBufferLists函数的功能:
NDIS调用一个Filter DriverFilterSendNetBufferLists例程来过滤上层驱动的发送请求。Filter Driver不能改变其它驱动传来的NET_BUFFER_LIST结构中的SourceHandle成员的值。它可以过滤数据并发送过滤的数据到下层驱动。
对每一个提交到FilterSendNetBufferListsNDIS_BUFFER_LIST,我们可做下面的操作。

1)可以把缓冲区通过 NdisFSendBufferLists 传递给下层驱动,NDIS 保证上下文空间对FilterDriver的有效性。过滤驱动可以在发送前修改缓冲区的内容。可以像处理自己引发的发送请求的缓冲区一样处理这个缓冲区。 
2)可以调用 NdisFSendNetBufferListsComplete 拒绝传递这个包 
3)排队缓冲区内容到本地的供以后处理。例如要在一定超时后处理或要接收到特定包后才处理等。如果支持这种处理方式就要支持取消请求的操作。 
4)可以拷贝缓冲区并引发一个发送请求。它类似自己引发一个发送请求,但必须先调用 NdisFSendNetBufferComplete返回上层驱动的缓冲区。

发送请求在驱动栈继续完成,当一个微端口驱动调用NdisMSendNetBufferListsComplete完成一个发送请求时,NDIS会调用微端口
驱动之上最近的Filter DriverFilterSendNetBufferLists例程。

在一个发送操作完成后,Filter Driver可以做在FilterSendNetBufferLists中所有修改的相反操作。FilterSendNetBufferListsComplete返回一个NET_BUFFER_LIST结构的单链表和发送请求的最终状态给上层的驱动。当最顶层的 Filter ModuleFilterSendNetBufferListsComplete被调用完成后NDIS会调用引发发送请求的协议驱动的ProtocolSendNetBufferListsComplete。如果Filter Driver不提供FilterSendNetBufferLists它还是可以引发一个发送操作的,但它必须提供一个FilterSendNetBufferListsComplete并且不能在这个例程里把这个事件传递给上层驱动。

一个Filter Driver可以传递或过滤一个上层驱动的回环请求,要传递一个回环请求,NDIS会设置FilterSendNetBufferListsSendFlags参数为NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK,Filter Driver在调用NdisFSendNetBufferLists时把这个标记传给它即可。在回环请求的情况下NDIS会指示一个包含发送数据的接收包。

通常情况下,如果一个Filter Driver修改的任何行为不是NDIS提供的标准服务,那么它应该当自己为NDIS提供相应的服务。例如,如果一个Filter Driver修改了一个硬件地址请求,就必须处理直接到这个新地址回环包。在这种情况下因为Filter Driver已经更改了地址NDIS是不能提供一个回环服务的。
还有就是如果Filter Driver设置了混杂模式那它就不能传递额外的数据给上层接收。 
**************************************************************/

VOID
FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags
)


{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNET_BUFFER_LIST CurrNbl;
BOOLEAN DispatchLevel;
BOOLEAN bFalse = FALSE;

DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists));

do
{

DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);

#if DBG 

FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

CurrNbl = NetBufferLists;
while (CurrNbl)
{
NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
NdisFSendNetBufferListsComplete(pFilter->FilterHandle, 
NetBufferLists, 
DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
break;

}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

/******************************************************/

//在这里添加我们的代码

/******************************************************/

if (pFilter->TrackSends)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
CurrNbl = NetBufferLists;
while (CurrNbl)
{
pFilter->OutstandingSends++;
FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);

CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}


NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);


}
while (bFalse);

DEBUGP(DL_TRACE, ("<===SendNetBufferList. \n"));
}




/*************************************************************
FilterReturnNetBufferLists函数的功能:
如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists
返回指示数据。在这种情况下 Filter Driver失去了对NET_BUFFER_LIST的所有权,直到FilterReturnNetBufferLists被调用。

Filter Driver调用NdisFIndicateNetBufferLists 传递接收指示给驱动栈上的上层驱动,如果上层驱动保留了对缓冲区(NET_BUFFER_LIST)的所有权,NDIS会调用Filter DriverFilterReturnNetBufferLists 例程。

FilterReturnNetBufferLists中应该撤消在接收路径上(如在 FilterReciveNetBufferLists中做的一些处理)的操作。当最底层的Filter Module完成对缓冲区(NET_BUFFER_LIST)的处理后,NDIS把缓冲区返回给微端口驱动。如果FilterReceiveNetBufferListsReceiveFlags没有设置NDIS_RECEIVE_FLAGS_RESOURCES标记, FilterDriver调用NdisFReturnNetBufferList返回这个缓冲区数据,如果设置了FilterReceiveNetBufferLists直接返回时就把缓冲区返还给了下层微端口驱动。 
***************************************************************/
VOID
FilterReturnNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG ReturnFlags
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NULL;
UINT NumOfNetBufferLists = 0;
BOOLEAN DispatchLevel;
ULONG Ref;

DEBUGP(DL_TRACE, ("===>ReturnNetBufferLists, NetBufferLists is %p.\n", NetBufferLists));

if (pFilter->TrackReceives)
{
while (CurrNbl)
{

NumOfNetBufferLists ++;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
}
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);

if (pFilter->TrackReceives)
{
DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL(ReturnFlags);
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

pFilter->OutstandingRcvs -= NumOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(3, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);



DEBUGP(DL_TRACE, ("<===ReturnNetBufferLists.\n"));


}



/***************************************************************
FilterReceiveNetBufferLists函数的功能:
Filter Driver调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。这个函数通过NET_BUFFER_LIST结构给上层驱动指示数据。Filter Driver可以从池中分配这个结构。如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为 NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists返回指示数据。在这种情况下Filter Driver失去了对NET_BUFFER_LIST的所有权直到FilterReturnNetBufferLists被调用。如果Filter Driver在调用NdisFIndicateReceiveNetBufferLists时设置ReceiveFlagsNDIS_RECEIVE_FLAGS_RESOURCES,在函数返回后Filter Driver会立即恢复对NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回,因为NDIS在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。 

注意一个Filter Driver应该跟踪自己引发的接收指示确保它在FilterReturnNetBufferLists
中不调用NdisFReturnNetBufferLists。 
***************************************************************/
VOID
FilterReceiveNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG NumberOfNetBufferLists,
IN ULONG ReceiveFlags
)

{

PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
ULONG Ref;
BOOLEAN bFalse = FALSE;


#if DBG
ULONG ReturnFlags;
#endif

DEBUGP(DL_TRACE, ("===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists));
do
{

DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))

ReturnFlags = 0;
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
{
NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
}

NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
}
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

ASSERT(NumberOfNetBufferLists >= 1);


/*--------------------------------------------------------------------------------------*/ 

//在这里添加我们的代码


/*---------------------------------------------------------------------------------------*/


if (pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs += NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;

FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}


/************************************************************
调用 NdisFIndicateReceiveNetBufferLists来指示发送数据。

如果Filter Driver设置了NdisFIndicateReceiveNetBufferLists的状态为NDIS_STATUS_SUCCESS, NDIS通过驱动的FilterReturnNetBufferLists 返回指示数据。

如果Filter Driver设置了NdisFIndicateReceiveNetBufferListsReceiveFlags值为
NDIS_RECEIVE_FLAGS_RESOURCES,那么在函数返回后Filter Driver会立即恢复对
NET_BUFFER_LIST的所有权,这时Filter Driver必须立即处理这个NET_BUFFER_LIST的返回。
在这种情况下是不会调用FilterReturnNetBufferLists返回NET_BUFFER_LIST结构的。
************************************************************/
NdisFIndicateReceiveNetBufferLists(
pFilter->FilterHandle,
NetBufferLists,
PortNumber, 
NumberOfNetBufferLists,
ReceiveFlags);


if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) && pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}

} while (bFalse);

DEBUGP(DL_TRACE, ("<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags));

}



/**************************************************************
FilterCancelSendNetBufferLists函数的功能:
过滤驱动调用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID宏为每一个NET_BUFFER_LIST标记一个取消Id
在为网络数据分配取消ID之前,必须先调用NdisGenratePartialCanceId获得取消ID的高字节。
这是为了确保不是驱动不会把一个取消ID分配给两个驱动驱动通常在DriverEntry调用
NdisGenratePartialCanceld,但是驱动可以在不同的时间多次调用它来获得多个取消ID
要取消被标记过取消ID且正在传输的数据,驱动可以调用NdisFCancelSendNetBufferLists例程
来完成。要获得取消ID可以用NDIS_GET_NET_BUFFER_LIST_CANCEL_ID宏来完成。

如果一个Filter Driver对所有发送的NET_BUFFER_LIST标记了相同的取消ID那它可以用一个 
NdisFCancelSendNetBufferLists来取消所有的发送请求。如果把一部发送请求的NET_BUFFER_LIST标记相同的取消ID那么就可以调用一次NdisFCancelSendNetBufferLists来取消这部分发送请求。

在实现这个功能时NDIS会调用下层驱动的取消发送功能。中断正在执行的发送任务后,下层驱动会
调用发送完成全程(:NdisMSendNetBufferListComplete)返回指定的NET_BUFFER_LIST结构并指定 返回状态为 NDIS_STATUS_CANCELLED, NDIS依次调用Filter DriverFilterSendNetBufferListsComplete例程。在FilterSendNetBufferListsComplete中要用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID设置取消的NET_BUFFER_LIST 
的取消ID 为 NULL,这样是为了防止这个ID,在 NET_BUFFER_LIST被再次分配时使用。 


上层驱动在取消一个未完成的发送请求时也必须对这个发送请求的 NET_BUFFER_LIST结构设定取消ID
NDIS会传递给Filter DriverFilterCancelSendNetBufferLists一个取消ID来取消发送请求的
NET_BUFFER_LIST发送。FilterCanCelSendNetBufferLists下执行下列操作。 
1)遍历 Filter Driver的发送队列,用 NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID获得队列中NET_BUFFER_LIST的取消IDFilterCancelSendBufferLists的取消ID比较。 
2)移除队列中取消 ID 和 FilterCancelSentBufferLists中取消ID相同的元素。 
3)调用 NdisFSendNetBufferListsComplete来完成这些NET_BUFFER_LIST并设定返回状
态为NDIS_STATUS_CANCELLED。 
4)调用NdisFCancelSendNetBufferLists传递取消发送请求给下层驱动。传递取消ID给下层驱动就Filter Driver取消自己引发的发关请求一样。 
*************************************************************/
VOID
FilterCancelSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PVOID CancelId
)

{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;

NdisFCancelSendNetBufferLists(pFilter->FilterHandle,CancelId);
}




/**************************************************************
FilterSetModuleOptions函数的功能:
必须要在初始化时为驱动注册FilterSetModuleOptions例程,驱动可以在这个例程中初始化
NDIS_FILTER_PARTIAL_CHARACTERISTICS结构来调用NdisSetOptionalHandlers来完成必变。
这个例程如果存在那么在调用Filter DriverFilterRestart例程之前调用它。
***************************************************************/ 
NDIS_STATUS
FilterSetModuleOptions(
IN NDIS_HANDLE FilterModuleContext
)
{

PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
BOOLEAN bFalse = FALSE;


if (bFalse)
{
UINT i;


pFilter->CallsRestart++;

i = pFilter->CallsRestart % 8;

pFilter->TrackReceives = TRUE;
pFilter->TrackSends = TRUE;

NdisMoveMemory(&OptionalHandlers, &DefaultChars, sizeof(OptionalHandlers));
OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;
OptionalHandlers.Header.Size = sizeof(OptionalHandlers);
switch (i)
{

case 0: 
OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
pFilter->TrackReceives = FALSE;
break;

case 1:

OptionalHandlers.ReturnNetBufferListsHandler = NULL;
pFilter->TrackReceives = FALSE;
break;

case 2:
OptionalHandlers.SendNetBufferListsHandler = NULL;
pFilter->TrackSends = FALSE;
break;

case 3:
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
pFilter->TrackSends = FALSE;
break;

case 4:
OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
OptionalHandlers.ReturnNetBufferListsHandler = NULL;
break;

case 5:
OptionalHandlers.SendNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
break;

case 6:

OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
OptionalHandlers.ReturnNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsHandler = NULL;
OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
break;

case 7:
break;
}
Status = NdisSetOptionalHandlers(pFilter->FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&OptionalHandlers );
}
return Status;
}



NDIS_STATUS
filterDoInternalRequest(
IN PMS_FILTER FilterModuleContext,
IN NDIS_REQUEST_TYPE RequestType,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
IN ULONG OutputBufferLength, OPTIONAL
IN ULONG MethodId, OPTIONAL
OUT PULONG pBytesProcessed
)

{
FILTER_REQUEST FilterRequest;
PNDIS_OID_REQUEST NdisRequest = &FilterRequest.Request;
NDIS_STATUS Status;
BOOLEAN bFalse;


bFalse = FALSE;
NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));

NdisInitializeEvent(&FilterRequest.ReqEvent);

NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
NdisRequest->RequestType = RequestType;

switch (RequestType)
{
case NdisRequestQueryInformation:
NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =InformationBuffer;

NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;

break;

case NdisRequestSetInformation:
NdisRequest->DATA.SET_INFORMATION.Oid = Oid;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =InformationBuffer;

NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =InformationBufferLength;

break;

case NdisRequestMethod:
NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;
NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer = InformationBuffer;

NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength = InformationBufferLength;

NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
break;



default:
FILTER_ASSERT(bFalse);
break;
}

NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;

Status = NdisFOidRequest(FilterModuleContext->FilterHandle,NdisRequest);


if (Status == NDIS_STATUS_PENDING)
{

NdisWaitEvent(&FilterRequest.ReqEvent, 0);
Status = FilterRequest.Status;
}


if (Status == NDIS_STATUS_SUCCESS)
{
if (RequestType == NdisRequestSetInformation)
{
*pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;
}

if (RequestType == NdisRequestQueryInformation)
{
*pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
}

if (RequestType == NdisRequestMethod)
{
*pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;
}

if (RequestType == NdisRequestMethod)
{
if (*pBytesProcessed > OutputBufferLength)
{
*pBytesProcessed = OutputBufferLength;
}
}
else
{

if (*pBytesProcessed > InformationBufferLength)
{
*pBytesProcessed = InformationBufferLength;
}
}
}


return (Status);
}



VOID
filterInternalRequestComplete(
IN NDIS_HANDLE FilterModuleContext,
IN PNDIS_OID_REQUEST NdisRequest,
IN NDIS_STATUS Status
)


{
PFILTER_REQUEST FilterRequest;

UNREFERENCED_PARAMETER(FilterModuleContext);

FilterRequest = CONTAINING_RECORD(NdisRequest, FILTER_REQUEST, Request);

FilterRequest->Status = Status;

NdisSetEvent(&FilterRequest->ReqEvent);
}

网络数据由在网络上发送和接收的数据包组成。 NDIS 提供了数据结构来描述它们, NDIS 
6.0 提供了如下数据结构: 
1) NET_BUFFER 
2) NET_BUFFER LIST 
3) NET_BUFFER_LIST_CONTEXT

在 NDIS 6.0 中,NET_BUFFER 是封闭网络数据的基本构建块。每一个 NET_BUFFER 都有
一个 MDL 链。这些 MDL映射的缓冲区地址是 NET_BUFFER 指定的数据空间。这种数据映射
同 NDIS 5.X 及之前的版本使用的 NDIS_PACKET 中的映射是一样的。NDIS 提供函数来管理这
些 MDL 链。 
多个NET_BUFFER可以被附加到(可以被串到)一个NET_BUFFER_LIS上。这些NET_BUFFER
被组织成一个以 NULL 结束的单链表。驱动或 NDIS仅创建一个 NET_BUFFER_LIST,应该修改
它的链表给它插入或删除一些 NET_BUFFER 结构。 
NET_BUFFER_LIST 结构中包含的信息中描述了所有被串到一个链表上的 NET_BUFFER 
构。如果 NET_BUFFER_LIST 需要上下文信息,可以分配额外的空间来存储一个
NET_BUFFER_LIST_CONTEXT 结构。NDIS 提供函数来分配、访问 NET_BUFFER_LIST_CONTEXT
中的数据。 
多个 NET_BUFFER_LIST 结构可以串成一个 NET_BUFFER_LIST 链表。它们可以被组织成一
个以 NULL 结尾的单向链表。驱动可以对这个链表直接进行插入、删除操作。 
NDIS 6.0 中使用的 NET_BUFFER 结构相似于 NDIS 5.X 以前使用的 NDIS_PACKET结构,每
一个 NET_BUFFER 结构中都包装了一个网络数据包。

1 NDIS中间层驱动程序 2 1.1 NDIS中间层驱动程序(NDIS Intermediate Drivers)概述 2 1.2 NDIS中间层驱动程序的用途 4 1.3 NDIS中间层驱动程序的开发环境 4 2 NDIS中间层驱动程序的开发 4 2.1 可分页和可丢弃代码 4 2.2 共享资源的访问同步 5 2.3 中间层驱动程序的DriverEntry函数 5 2.3.1 注册NDIS中间层驱动程序 6 2.3.1.1 注册中间层驱动程序的Miniport 6 2.3.1.2 注册中间层驱动程序的协议 8 2.4 中间层驱动程序的动态绑定 11 2.4.1 打开中间层驱动程序下层的适配器 12 2.4.2 微端口(Miniport)初始化 12 2.4.3 中间层驱动程序查询和设置操作 13 2.4.3.1 发布设置和查询请求 14 2.4.3.2 响应设置和查询请求 15 2.4.4 作为面向连接客户程序注册中间层驱动程序 15 2.5 中间层驱动程序数据包管理 17 2.5.1.1 重用数据包 18 2.6 中间层驱动程序的限制 19 2.7 中间层驱动程序接收数据 19 2.7.1 下边界面向无连接的中间层驱动程序接收数据 19 2.7.1.1 在中间层驱动程序中实现ProtocolReceivePacket处理程序 20 2.7.1.2 在中间层驱动程序中实现ProtocolReceive处理程序 21 2.7.1.3 下边界面向无连接中间层驱动程序接收OOB数据信息 22 2.7.2 下边界面向连接的中间层驱动程序接收数据 22 2.7.2.1 在中间层驱动程序中实现ProtocolCoReceivePacket处理程序 23 2.7.2.2 在下边界面向连接的中间层驱动程序中接收OOB数据信息 23 2.7.3 向高层驱动程序指示接收数据包 23 2.8 通过中间层驱动程序传输数据包 23 2.8.1 传递介质相关信息 25 2.9 处理中间层驱动程序的PnP事件和PM事件 26 2.9.1 处理OID_PNP_XXX查询和设置 26 2.9.2 中间层驱动程序ProtocolPnPEvent处理程序的实现 27 2.9.3 处理规定的电源请求 28 2.9.3.1 睡眠状态的电源设置请求 28 2.9.3.2 工作状态的电源设置请求 29 2.10 中间层驱动程序复位操作 29 2.11 中间层驱动程序拆除绑定操作 30 2.12 中间层驱动程序状态指示 31 3 负载平衡和失效替换 31 3.1 关于LBFO 31 3.2 指定对LBFO的支持 32 3.3 在微端口驱动程序上实现LBFO 32 3.3.1 初始化微端口束 33 3.3.2 平衡微端口驱动程序的工作量 33 3.3.3 在主微端口失效后提升一个次微端口 34 4 安装网络组件 34 4.1 用于安装网络组件的组件和文件 34 4.2 创建网络INF文件 35 4.2.1 网络INFS文件名的约定 35 4.2.2 网络INF文件的版本节 35 4.2.3 网络INF文件的模型节 36 4.2.4 INF文件的DDInstall节 37 4.2.5 删除节 38 4.2.6 ControlFlags节 39 4.2.7 网络INF文件的add-registry-sections 39
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值