和NIC小端口驅動不同的是,無需考慮網絡數據具體是如何傳輸的,只需要針對NBL進行處理即可。Filter驅動程序可以啟動發送請求和接收指示,或“過濾”其他驅動程序的請求和指示。Filter模塊堆疊在微型端口適配器上。
驅動程序堆棧中的Filter模塊可以篩選與基礎適配器關聯的所有發送請求和接收指示。 這適用于適配器的所有協議綁定。
Filter驅動程序不直接支持基于 NDIS_PACKET 結構的舊發送和接收操作。 相反,NDIS 將接收來自舊微型端口驅動程序的指示轉換為 NET_BUFFER 結構。 此外,NDIS 還處理從基于NET_BUFFER結構的發送請求到基于NDIS_PACKET結構的舊發送請求的所需轉換。
Filter驅動程序緩沖區管理
Filter驅動程序創建緩沖區以復制從其他驅動程序獲取的網絡數據,或啟動發送或接收操作。
如果Filter驅動程序不創建緩沖區,則驅動程序不會管理緩沖池。 此類驅動程序只是傳遞它從其他驅動程序接收的緩沖區。
創建緩沖區以支持發送或接收操作的Filter驅動程序必須管理 NET_BUFFER_LIST 結構池和 NET_BUFFER 結構池。
若要創建這些池,驅動程序會調用以下函數:
- NdisAllocateNetBufferListPool
- NdisAllocateNetBufferPool
Filter驅動程序可以使用以下函數從池中分配結構:
- NdisAllocateNetBufferAndNetBufferList
- NdisAllocateNetBufferList
- NdisAllocateNetBuffer
調用 NdisAllocateNetBufferAndNetBufferList 比調用 NdisAllocateNetBufferList 和 NdisAllocateNetBuffer 更高效。 但是, NdisAllocateNetBufferAndNetBufferList 僅在NET_BUFFER_LIST結構上創建一個NET_BUFFER結構。 若要使用 NdisAllocateNetBufferAndNetBufferList,驅動程序必須在調用 NdisAllocateNetBufferListPool 時將 AllocateNetBuffer 參數設置為 TRUE。
源自發送請求的Filter驅動程序應確定基礎驅動程序的上下文和回填空間要求。 Filter驅動程序使用重啟屬性來確定基礎驅動程序的回填要求。 Filter驅動程序應確定處于 “正在重啟” 狀態的回填和上下文要求。 驅動程序應為整個堆棧分配足夠的回填和上下文空間。 如有必要,Filter驅動程序可以釋放池并將其重新分配為 “正在重啟” 狀態。
Filter驅動程序使用以下函數來釋放池:
- NdisFreeNetBufferListPool
- NdisFreeNetBufferPool
Filter驅動程序使用以下函數釋放從池中分配的結構:
- NdisFreeNetBufferList
- NdisFreeNetBuffer
在釋放關聯的NET_BUFFER_LIST結構之前,驅動程序應釋放使用 NdisAllocateNetBuffer 分配NET_BUFFER結構。 當驅動程序為關聯的NET_BUFFER_LIST結構調用 NdisFreeNetBufferList 時,將釋放使用 NdisAllocateNetBufferAndNetBufferList 分配的NET_BUFFER結構。
從Filter驅動程序發送數據
發送Filter驅動程序啟動的請求
Filter驅動程序可以啟動發送請求或過濾驅動程序啟動的發送請求。 當協議驅動程序調用 NdisSendNetBufferLists 函數時,NDIS 會將指定的 NET_BUFFER_LIST 結構提交到驅動程序堆棧中最頂層的Filter模塊,下圖演示了Filter驅動程序啟動的發送操作。
Filter驅動程序調用 NdisFSendNetBufferLists 函數以發送 在NET_BUFFER_LIST 結構列表中定義的網絡數據。
Filter驅動程序必須將它創建的每個NET_BUFFER_LIST結構的 SourceHandle 成員設置為它傳遞給 NdisFSendNetBufferLists 的 NdisFilterHandle 參數的相同值。 NDIS 驅動程序不應修改該驅動程序未源自NET_BUFFER_LIST結構的 SourceHandle 成員。
在調用 NdisFSendNetBufferLists 之前,Filter驅動程序可以設置隨 NET_BUFFER_LIST_INFO 宏一起發送請求的信息。 基礎驅動程序可以使用 NET_BUFFER_LIST_INFO 宏檢索此信息。
Filter驅動程序一旦調用 NdisFSendNetBufferLists,就會放棄NET_BUFFER_LIST結構和所有關聯資源的所有權。 NDIS 可以處理發送請求或將請求傳遞給基礎驅動程序。
NDIS 調用 FilterSendNetBufferListsComplete 函數,將結構和數據返回到Filter驅動程序。 在將列表傳遞給 FilterSendNetBufferListsComplete 之前,NDIS 可以將多個發送請求中的結構和數據收集到NET_BUFFER_LIST結構的單個鏈接列表中
在 NDIS 調用 FilterSendNetBufferListsComplete 之前,發送請求的當前狀態是未知的。 在 NDIS 將結構返回到 FilterSendNetBufferListsComplete 之前,Filter驅動程序絕不應嘗試檢查NET_BUFFER_LIST結構或任何關聯數據。
FilterSendNetBufferListsComplete 執行完成發送操作所需的任何后處理。
當 NDIS 調用 FilterSendNetBufferListsComplete 時,Filter驅動程序將重新獲得與 NetBufferLists 參數指定的NET_BUFFER_LIST結構關聯的所有資源的所有權。 FilterSendNetBufferListsComplete 可以釋放這些資源 ,例如,通過調用 NdisFreeNetBuffer 和 NdisFreeNetBufferList 函數?,或者準備在后續調用 NdisFSendNetBufferLists 時重復使用。
NDIS 始終按照傳遞給 NdisFSendNetBufferLists 的Filter驅動程序確定的順序向基礎驅動程序提交Filter提供的網絡數據。 但是,按指定順序發送數據后,基礎驅動程序可以按任意順序返回緩沖區。
Filter驅動程序可以請求其發起的發送請求的環回。 若要請求環回,驅動程序在 NdisFSendNetBufferLists 的 SendFlags 參數中設置NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK標志。 NDIS 指示包含發送數據的已接收數據包。
注意 Filter驅動程序應跟蹤其發起的發送請求,并確保在此類請求完成時不會調用 NdisFSendNetBufferListsComplete 函數。
過濾發送請求
下圖說明了如何過濾由過度分配的驅動程序發起的發送請求:
NDIS 調用Filter驅動程序的 FilterSendNetBufferLists 函數來篩選過大驅動程序的發送請求。
Filter驅動程序不得修改從其他驅動程序接收的 NET_BUFFER_LIST 結構中的 SourceHandle 成員。
Filter驅動程序可以篩選數據并將篩選的數據發送到基礎驅動程序。 對于提交到 FilterSendNetBufferLists 的每個NET_BUFFER結構,Filter驅動程序可以執行以下操作:
- 通過調用 NdisFSendNetBufferLists 函數,將緩沖區傳遞到下一個基礎驅動程序。 NDIS 保證上下文空間的可用性, 查看Filter驅動程序 NET_BUFFER_LIST_CONTEXT結構。 Filter驅動程序可以在調用 NdisFSendNetBufferLists 之前修改緩沖區內容。 篩選數據的處理與Filter驅動程序啟動的發送操作一樣進行;
- 通過調用 NdisFSendNetBufferListsComplete 函數刪除緩沖區;
- 在本地數據結構中將緩沖區排隊,供以后處理。 Filter驅動程序的設計決定了導致驅動程序處理排隊緩沖區的原因。 一些示例包括超時后的處理或在收到特定緩沖區后進行處理。注意 如果驅動程序將發送請求排隊以供以后處理,則必須支持發送取消請求。 有關發送取消請求的詳細信息,請參閱 在Filter驅動程序中取消發送請求;
- 復制緩沖區,并使用副本發起發送請求。 發送操作類似于Filter驅動程序發起的發送請求。 在這種情況下,驅動程序必須通過調用 NdisFSendNetBufferListsComplete 函數,將原始緩沖區返回到上置驅動程序;
完成發送請求會繼續上行驅動程序堆棧。 當微型端口驅動程序調用 NdisMSendNetBufferListsComplete 函數時,NDIS 將調用 FilterSendNetBufferListsComplete 函數以獲取最低覆蓋Filter模塊。
發送操作完成后,Filter驅動程序將反轉對Filter驅動程序在 FilterSendNetBufferLists 中對過度覆蓋驅動程序的緩沖區描述符的修改。 驅動程序調用 NdisFSendNetBufferListsComplete 函數,以將NET_BUFFER_LIST結構的鏈接列表返回到上部驅動程序,并返回發送請求的最終狀態。
當最頂層的Filter模塊調用 NdisFSendNetBufferListsComplete 時,NDIS 將調用原始協議驅動程序的 ProtocolSendNetBufferListsComplete 函數。
不提供 FilterSendNetBufferLists 函數的Filter 驅動程序仍然可以啟動發送請求。 如果此類驅動程序確實啟動發送請求,則必須提供 FilterSendNetBufferListsComplete 函數,并且不得在驅動程序堆棧上傳遞完整事件。
Filter驅動程序可以傳遞或篩選過大驅動程序的環回請求。 若要傳遞環回請求,如果 NDIS 在 FilterSendNetBufferLists 的 SendFlags 參數中設置NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK,Filter驅動程序在調用 NdisFSendNetBufferLists 時在 SendFlags 參數中設置NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK。 NDIS 指示包含發送數據的已接收數據包。
通常,如果Filter驅動程序以 NDIS 無法提供標準服務(如環回 )的方式修改任何行為,則Filter驅動程序必須為 NDIS 提供該服務。 例如,修改硬件地址請求 ( OID_802_3_CURRENT_ADDRESS) 的Filter驅動程序應處理定向到新硬件地址的緩沖區的環回。 在這種情況下,NDIS 無法提供它通常提供的環回服務,因為Filter更改了地址。 此外,如果Filter驅動程序設置雜亂模式 ,例如OID_GEN_CURRENT_PACKET_FILTER),則它不應將其收到的額外數據傳遞給過度覆蓋的驅動程序。
取消Filter驅動程序中的發送請求
Filter驅動程序可以取消發送由Filter驅動程序發起或由過度分配驅動程序發起的請求。
取消Filter驅動程序發送請求
下圖說明了如何取消由Filter驅動程序發起的發送請求:
Filter驅動程序為它為發送操作創建的每個NET_BUFFER_LIST結構調用 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID宏。 NDIS_SET_NET_BUFFER_LIST_CANCEL_ID 函數使用取消標識符標記指定的數據。
在將取消 ID 分配給網絡數據之前,Filter驅動程序必須調用 NdisGeneratePartialCancelId 以獲取它分配的每個取消 ID 的高序字節。 這可確保驅動程序不會重復系統中其他驅動程序分配的取消 ID。 驅動程序通常從 DriverEntry 例程調用 NdisGeneratePartialCancelId 一次。 但是,驅動程序可以通過多次調用 NdisGeneratePartialCancelId 來獲取多個部分取消標識符。
若要取消標記NET_BUFFER_LIST結構中數據的掛起傳輸,Filter驅動程序會將取消 ID 傳遞給 NdisFCancelSendNetBufferLists 函數。 驅動程序可以通過調用 NDIS_GET_NET_BUFFER_LIST_CANCEL_ID 宏來獲取 NET_BUFFER_LIST 結構的取消 ID。
如果Filter驅動程序使用相同的取消標識符標記所有NET_BUFFER_LIST結構,則只需調用 NdisFCancelSendNetBufferLists 即可取消所有掛起的傳輸。 如果Filter驅動程序使用唯一標識符標記NET_BUFFER_LIST結構的子組中的所有NET_BUFFER_LIST結構,則只需調用 NdisFCancelSendNetBufferLists 即可取消該子組中所有掛起的傳輸。
NDIS 調用基礎驅動程序的取消發送函數。 中止掛起的傳輸后,基礎驅動程序調用 send complete 函數 (例如 NdisMSendNetBufferListsComplete) ,以返回完成狀態為NDIS_STATUS_SEND_ABORTED的NET_BUFFER_LIST結構。 NDIS 又調用Filter驅動程序的 FilterSendNetBufferListsComplete 函數。
在 FilterSendNetBufferListsComplete 中,Filter驅動程序可以在 CancelId 設置為 NULL 的情況下調用NDIS_SET_NET_BUFFER_LIST_CANCEL_ID。 這可以防止NET_BUFFER_LIST意外地再次使用過時的取消 ID。
取消發送由過度覆蓋驅動程序發出的請求?
?下圖說明了如何取消由過度分配的驅動程序發起的發送請求:
過度調用驅動程序 ( NdisFCancelSendNetBufferLists 或 NdisCancelSendNetBufferLists) 取消未完成的發送請求。 在發出發送請求之前,這些過度的驅動程序必須使用取消 ID 標記發送數據。
NDIS 調用Filter驅動程序的 FilterCancelSendNetBufferLists 函數來取消所有標有指定取消標識符的 NET_BUFFER_LIST 結構的傳輸。
FilterCancelSendNetBufferLists 執行以下操作:
- 遍歷指定Filter模塊的已排隊NET_BUFFER_LIST結構的Filter驅動程序列表,并調用 NDIS_GET_NET_BUFFER_LIST_CANCEL_ID 宏以獲取每個結構的取消標識符。 Filter驅動程序將NDIS_GET_NET_BUFFER_LIST_CANCEL_ID返回的取消 ID 與 NDIS 傳遞給 FilterCancelSendNetBufferLists 的取消 ID 進行比較;
- 從發送隊列中刪除 (取消鏈接) 其取消標識符與指定取消標識符匹配的所有NET_BUFFER_LIST結構;
- 為所有未鏈接的NET_BUFFER_LIST結構調用 NdisFSendNetBufferListsComplete 函數以返回結構。 Filter驅動程序將NET_BUFFER_LIST結構的狀態字段設置為NDIS_STATUS_SEND_ABORTED;
- 調用 NdisFCancelSendNetBufferLists 函數,將取消發送請求傳遞給基礎驅動程序。 Filter驅動程序傳遞它從過度的驅動程序收到的取消標識符。 取消操作與Filter驅動程序發起的取消發送操作一樣繼續;
在Filter驅動程序中接收數據
Filter驅動程序可以啟動接收指示,也可以從基礎驅動程序啟動Filter接收指示。 當微型端口驅動程序調用 NdisMIndicateReceiveNetBufferLists 函數時,NDIS 會將指定的 NET_BUFFER_LIST 結構提交到驅動程序堆棧中最低的過度篩選模塊。
接收Filter驅動程序啟動的指示
下圖演示了Filter驅動程序啟動的接收指示。
Filter驅動程序調用 NdisFIndicateReceiveNetBufferLists 函數來指示收到的數據。 NdisFIndicateReceiveNetBufferLists 函數將堆棧上NET_BUFFER_LIST結構的指示列表傳遞給超載驅動程序。 Filter驅動程序從它在初始化期間創建的池中分配結構。
如果Filter驅動程序在 NdisFIndicateReceiveNetBufferLists 的 ReceiveFlags 參數中設置NDIS_RECEIVE_FLAGS_RESOURCES標志,則表示Filter驅動程序必須立即重新獲得NET_BUFFER_LIST結構的所有權。 在這種情況下,NDIS 不會調用Filter驅動程序的 FilterReturnNetBufferLists 函數來返回 NET_BUFFER_LIST 結構。 Filter驅動程序在 NdisFIndicateReceiveNetBufferLists 返回后立即重新獲得所有權。
如果Filter驅動程序未在 NdisFIndicateReceiveNetBufferLists 的 ReceiveFlags 參數中設置NDIS_RECEIVE_FLAGS_RESOURCES標志,則 NDIS 會將指示的NET_BUFFER_LIST結構返回到Filter驅動程序的 FilterReturnNetBufferLists 函數。 在這種情況下,Filter驅動程序將放棄所指示結構的所有權,直到 NDIS 將它們返回到 FilterReturnNetBufferLists。
注意 Filter驅動程序應跟蹤它啟動的接收指示,并確保它在接收操作完成時不調用 NdisFReturnNetBufferLists 函數。
過濾接收指示
下圖演示了基礎驅動程序啟動的過濾接收指示:
NDIS 調用Filter驅動程序的 FilterReceiveNetBufferLists 函數來處理來自基礎驅動程序的接收指示。 NDIS 在基礎驅動程序調用接收指示函數后調用 FilterReceiveNetBufferLists , (例如 ,NdisMIndicateReceiveNetBufferLists) 來指示接收的網絡數據或環回數據。
如果未設置 FilterReceiveNetBufferLists 的 ReceiveFlags 參數中的NDIS_RECEIVE_FLAGS_RESOURCES標志,Filter驅動程序將保留NET_BUFFER_LIST結構的所有權,直到調用 NdisFReturnNetBufferLists 函數。
如果設置了 ReceiveFlags 參數中的NDIS_RECEIVE_FLAGS_RESOURCES標志,則Filter驅動程序無法保留NET_BUFFER_LIST結構和關聯的基礎驅動程序分配的資源。 此標志可以指示基礎驅動程序的接收資源不足。 FilterReceiveNetBufferLists 函數應盡快返回。
注意 如果設置了 NDIS_RECEIVE_FLAGS_RESOURCES 標志,Filter驅動程序必須在鏈接列表中保留原始 NET_BUFFER_LIST 結構集。 例如,當設置此標志時,驅動程序可能會處理結構,并一次一個地在堆棧上指示它們,但在函數返回之前,它必須還原原始鏈接列表。
Filter驅動程序可以先對收到的數據執行篩選操作,然后再將數據指示給過度覆蓋的驅動程序。 對于提交到 FilterReceiveNetBufferLists 函數的每個緩沖區,Filter驅動程序可以執行以下操作:
- 通過調用 NdisFIndicateReceiveNetBufferLists,將其傳遞給下一個過度覆蓋的驅動程序。 驅動程序可以修改緩沖區的內容。 NDIS 保證上下文空間的可用性, 通過查看 NET_BUFFER_LIST_CONTEXT結構;Filter驅動程序可以更改 NDIS 傳遞到 FilterReceiveNetBufferLists 的狀態,也可以直接將其傳遞給 NdisFIndicateReceiveNetBufferLists。注意即使 NDIS 在 FilterReceiveNetBufferLists 的ReceiveFlags 參數中設置了 NDIS_RECEIVE_FLAGS_RESOURCES 標志,Filter驅動程序也可以使用 NdisFIndicateReceiveNetBufferLists 傳遞緩沖區。 在這種情況下,Filter驅動程序不得從 FilterReceiveNetBufferLists 返回,直到它重新獲得緩沖區的所有權;
- 放棄緩沖區。 如果 NDIS 清除 FilterReceiveNetBufferLists 的 ReceiveFlags 參數中的NDIS_RECEIVE_FLAGS_RESOURCES標志,請調用 NdisFReturnNetBufferLists 函數以放棄緩沖區。 如果 NDIS 在 FilterReceiveNetBufferLists 的 ReceiveFlags 參數中設置NDIS_RECEIVE_FLAGS_RESOURCES標志,則不執行任何操作,并從 FilterReceiveNetBufferLists 返回以放棄緩沖區;
- 在本地數據結構中將緩沖區排隊,供以后處理。 如果 NDIS 在 FilterReceiveNetBufferLists 的 ReceiveFlags 參數中設置NDIS_RECEIVE_FLAGS_RESOURCES標志,則Filter驅動程序必須在從 FilterReceiveNetBufferLists 返回之前創建副本;
- 復制緩沖區,并使用副本生成接收指示。 接收指示類似于Filter驅動程序啟動的接收指示。 在這種情況下,驅動程序必須將原始緩沖區返回到基礎驅動程序;
NdisFIndicateReceiveNetBufferLists 函數將指示的NET_BUFFER_LIST結構列表傳遞到驅動程序堆棧上到過度覆蓋的驅動程序。 接收操作的繼續方式類似于Filter驅動程序發起的接收操作。
如果過分驅動程序保留了緩沖區的所有權,NDIS 會為Filter模塊調用 FilterReturnNetBufferLists 函數。 在其 FilterReturnNetBufferLists 函數中,Filter驅動程序將撤消它在接收指示路徑上的緩沖區上執行的操作。
當最低層Filter模塊指示它已使用緩沖區完成時,NDIS 會將緩沖區返回到微型端口驅動程序。 如果 NDIS 清除 FilterReceiveNetBufferLists 的 ReceiveFlags 參數中的 NDIS_RECEIVE_FLAGS_RESOURCES 標志,則Filter驅動程序會調用 NdisFReturnNetBufferLists 以返回緩沖區。 如果 NDIS 在 FilterReceiveNetBufferLists 的 ReceiveFlags 參數中設置NDIS_RECEIVE_FLAGS_RESOURCES標志,則從 FilterReceiveNetBufferLists 返回將返回緩沖區。