2011年7月22日星期五

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

來源網絡
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.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_OFF​​SET 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 = At​​tachParameters->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 = At​​tachParameters->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 = At​​tachParameters->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 = At​​tachParameters->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 Con​​figurationHandle = 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 狀態。 
   
  注意:Fil​​ter 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為ND​​IS_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); 
}

没有评论:

发表评论