轉帖 NDIS中間層驅動開發在Win7系統下和Windows XP系統下的區別

NDIS中間層驅動的開發在Win7系統上和Windows XP系統上有差異。
原帖:http://bbs.pediy.com/showthread.php?t=137545
 我把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.0或V5.0的MiniportXxx函數,那麼中間層驅動程序的主版本必須是V4.0,而且提供4.0或5.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.0或5.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;
  }

//若是驅動程序導出了MiniportXxx和ProtocolXxx這一些列的函數,那麼就調用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種類型的回調函數MiniportXXX和ProtocolXXX 在新的框架裏面被所有隱藏起來了。
微軟提供了新的函數。 一塊兒來看看,微軟提供了什麼。
在這裏,爲了方便分析, 我把函數代碼都作了功能註釋,請你們一塊兒看看。
代碼以下:


#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;      // 協議,多是TCP、UDP、ICMP等
  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;    //16位TCP檢驗和
  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 Attach的NdisFilterHandle做爲輸入來調用NdisFSetAttributes例程。


   Attach is complete
   當Filter Module在Attaching狀態下而且Filter Driver初始化了全部的Filter Module所須要的
   全部資源時,Filter Module進入Paused狀態。


   參數說明:
    NdisFilterHandle     它用於全部過濾驅動中對Ndisxxx類例程的調用時引用指示這個過濾模塊。
    FilterDriverContext  它由NdisFRegisterFilterDriver的FilterDriverContext來指定。
    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 Module在Restarting狀態下而且完成全部發送和接收所須要的準備工做時,Filter Module就進入了Running狀態。

要啓動一個Paused狀態的Filter Module,若是有FilterSetModuleOptions就先調用它,接着調用FilterRestart。

  當Filter Module在Restarting狀態下,它能夠:
  (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不能啓動返回了失敗,而它又是一個Mandatory的Filter Driver 那個 NDIS將會結束這個驅動棧
在一個Filter Driver完成對發送和接收的重啓後必須指示完成這個重啓操做。 
Filter Driver的重啓操做的完成能夠是同步也能夠是異步的,同步時返回 NDIS_STATUS_SUCCESS 異步時返回NDIS_STATUS_PENDING。若是返回的是 NDIS_STATUS_PENDING 就必須調用NdisFRestartComplete 例程在重啓操做完成後。
在這種狀況下,驅動須要傳遞給NdisFRestartComplete 一個固定狀態(標識重啓結果的成功或失敗狀態)。

重啓操做完成Filter Module就進入了 Running狀態,恢得一切正常的發送和接收外理。
在Filter Driver的FilterRestart例程執行的時候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  它由NdisFRegisterFilterDriver的FilterDriverContext來指定。
 ************************************************************/
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 Driver的FilterOidRequest例程來處理OID請求,Filter Driver須要調用NdisFOidRequest例程來轉發請求給下層驅動。 

  Filter Driver能夠從FilterOidRequest同步和異步完成一個OID請求,分別返回NDIS_STATS_SUCCESS和NDIS_STATUS_PENDING便可。FilterOidRequest能夠用同步的直接完成一個OID請求並返回一個錯誤狀態。 

  若是FilterOidRequest返回NDIS_STATUS_PENDING,就必須在OID請求完成後調用
  NdisFOidRequestComplete來通知上層驅動求請求完成。在這種狀況下,請求的結果經過
  NdisFOidRequestComplete的OidRequest參數返回給上層驅動,並經過Status參數返回請求完成的最終狀態。
   

  若是FilterOidRequest返回NDIS_STATUS_SUCCESS,經過FilterOidRequest的OidRequest參數返回一個查詢結果到上層。這時不調用 NdisFOidRequestComplete例程。 


  要轉發OID請求到下層驅動,Filter Driver必須調用NdisFOidRequest。若是一個OID請求不能被轉發到下層驅動應該當當即返回。要完成一個請求且不轉發能夠直接返回NDIS_STATUS_SUCCESS或其它錯誤狀態或返回 NDIS_STATUS_PENDING 後調用NdisFOidRequestComplete。 


  若是NdisFOidRequest返回NDIS_STATUS_PENDING,NDIS在OID請求完成後調用FilterOidRequestComplete來通知求請求完成在這種狀況下,請求的結果經過NdisFOidRequestComplete的OidRequest參數返回給上層驅動,並經過 Status 參數返回請求完成的最終狀態。
   

  若是 NdisFOidRequest返回NDIS_STATUS_SUCCESS,經過NdisFOidRequest的OidRequest參數返回一個查詢結果到上層。這時不調用FilterOidRequestComplete例程。 
  一個Filter Driver能夠調用NdisFOidRequest引起OID請求在Restarting、Running、Pausing和Paused 狀態。 
  
  注意: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 來通知上層驅動求請求完成。在這種狀況下,請求的結果經過NdisFOidRequestComplete的OidRequest參數返回給上層驅動,並經過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還能夠本身引起一個狀態指示。

當下層驅動調用一個狀態指示例程時(NdisMIndicateStatusEx或NdisFIndicateStats),NDIS
會調用Filter Driver的FilterStatus例程。

Filter Driver在FilterStatus中調用NdisFIndicateStatus傳遞一個狀態指示給上層驅動。此外,還能夠過濾狀態指示(不用調用 NdisFIndicateStatus)或在調用 NdisFIndicateStatus以前修改狀態信息。
  
   
Filter Driver要本身引起一個狀態報告,能夠在NDIS未調用 FilterStatus的狀況下調用NdisFIndicateStatus。在這種狀況下,Filter Driver要設置 SourceHandle 成員爲 FilteAttech 參數提供的NdisFilterHandle句柄。
若是一個狀態指示是一個OID請求相關的(下層請求一個 OID 下層要作相應的狀態指示),那麼狀態的DestinationHandle和RequestId成員要設置成上層的OID請求包攜帶的數據。 
  

Filter Driver調用NdisFIndicateStatus後NDIS會調用相鄰上層的狀態指示函數(ProtocolStatusEx或FilterStatus)。 
****************************************************************/
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 Driver。NDIS能夠收集屢次NdisFSendNetBufferLists發送的結構和數據造成一個單鏈表傳遞給FilterSendNetBufferListsComplete。除非到NDIS調用FilterSendNetBufferListsComplete,不然一個發送請求的當前狀態老是未知的。

  一個過濾驅動是不能在NDIS調用FilterSendNetBufferListsComplete返回結構以前對NET_BUFFER_LIST和其關聯的數據作檢查的。FilterSendNetBufferListsComplete要完成一個發送請求完成後的任何須要的後繼處理。當NDIS調用FilterSendNetBufferListsComplete時,Filter Driver就從新獲地對結構及結構相關資源的全部權。能夠在 FilterSendNetBufferListsComplete中釋放相關的資源和準備下一個NdisFSendNetBufferLists調用。 
 
  NDIS老是按照過濾驅動調用NdisFSendNetBufferLists提交的順序傳遞給下層驅動,可是回返FilterSendNetBufferListsComplete 的順序則是任意的。Filter Driver能夠請求一個迴環發送請求,只要把NdisFSendNetBufferLists的SendFlags設置成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 Driver的FilterSendNetBufferLists例程來過濾上層驅動的發送請求。Filter Driver不能改變其它驅動傳來的NET_BUFFER_LIST結構中的SourceHandle成員的值。它能夠過濾數據併發送過濾的數據到下層驅動。
  對每個提交到FilterSendNetBufferLists的NDIS_BUFFER_LIST,咱們可作下面的操做。
   
  1)能夠把緩衝區經過 NdisFSendBufferLists 傳遞給下層驅動,NDIS 保證上下文空間對FilterDriver的有效性。過濾驅動能夠在發送前修改緩衝區的內容。能夠像處理本身引起的發送請求的緩衝區同樣處理這個緩衝區。   
  2)能夠調用 NdisFSendNetBufferListsComplete 拒絕傳遞這個包 
  3)排隊緩衝區內容到本地的供之後處理。例如要在必定超時後處理或要接收到特定包後才處理等。若是支持這種處理方式就要支持取消請求的操做。     
  4)能夠拷貝緩衝區並引起一個發送請求。它相似本身引起一個發送請求,但必須先調用 NdisFSendNetBufferComplete返回上層驅動的緩衝區。
      
  發送請求在驅動棧繼續完成,當一個微端口驅動調用NdisMSendNetBufferListsComplete完成一個發送請求時,NDIS會調用微端口
  驅動之上最近的Filter Driver的FilterSendNetBufferLists例程。
  
  在一個發送操做完成後,Filter Driver能夠作在FilterSendNetBufferLists中全部修改的相反操做。FilterSendNetBufferListsComplete返回一個NET_BUFFER_LIST結構的單鏈表和發送請求的最終狀態給上層的驅動。當最頂層的 Filter Module的FilterSendNetBufferListsComplete被調用完成後NDIS會調用引起發送請求的協議驅動的ProtocolSendNetBufferListsComplete。若是Filter Driver不提供FilterSendNetBufferLists它仍是能夠引起一個發送操做的,但它必須提供一個FilterSendNetBufferListsComplete而且不能在這個例程裏把這個事件傳遞給上層驅動。

  一個Filter Driver能夠傳遞或過濾一個上層驅動的迴環請求,要傳遞一個迴環請求,NDIS會設置FilterSendNetBufferLists的SendFlags參數爲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 Driver的FilterReturnNetBufferLists 例程。
  
  在FilterReturnNetBufferLists中應該撤消在接收路徑上(如在 FilterReciveNetBufferLists中作的一些處理)的操做。當最底層的Filter Module完成對緩衝區(NET_BUFFER_LIST)的處理後,NDIS把緩衝區返回給微端口驅動。若是FilterReceiveNetBufferLists的ReceiveFlags沒有設置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時設置ReceiveFlags爲NDIS_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設置了NdisFIndicateReceiveNetBufferLists的ReceiveFlags值爲
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 Driver的FilterSendNetBufferListsComplete例程。在FilterSendNetBufferListsComplete中要用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID設置取消的NET_BUFFER_LIST 
 的取消ID 爲 NULL,這樣是爲了防止這個ID,在 NET_BUFFER_LIST被再次分配時使用。 


上層驅動在取消一個未完成的發送請求時也必須對這個發送請求的 NET_BUFFER_LIST結構設定取消ID。
 NDIS會傳遞給Filter Driver的FilterCancelSendNetBufferLists一個取消ID來取消發送請求的
 NET_BUFFER_LIST發送。FilterCanCelSendNetBufferLists下執行下列操做。  
  1)遍歷 Filter Driver的發送隊列,用 NDIS_GET_NET_BUFFER_LSIT_CANCEL_ID得到隊列中NET_BUFFER_LIST的取消ID與FilterCancelSendBufferLists的取消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 Driver的FilterRestart例程以前調用它。
 ***************************************************************/ 
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);
php

相關文章
相關標籤/搜索