NDIS 定義對象標識符 (OID) 值,以標識適配器參數,其中包括設備特征、可配置設置和統計信息等操作參數。 協議驅動程序可以查詢或設置基礎驅動程序的操作參數。
NDIS 還為 NDIS 6.1 及更高版本的協議驅動程序提供直接 OID 請求接口。 直接 OID 請求路徑支持頻繁查詢或設置的 OID 請求。 例如,IPsec 卸載版本 2 (IPsecv2) 接口為直接 OID 請求提供 OID_TCP_TASK_IPSEC_OFFLOAD_V2_ADD_SA OID。 直接 OID 請求接口對于 NDIS 驅動程序是可選的。
從 NDIS 協議驅動程序生成 OID 請求
為了向基礎驅動程序發出 OID 請求,協議調用 NdisOidRequest 函數。
下圖演示了協議驅動程序發起的 OID 請求。
在協議驅動程序調用 NdisOidRequest 函數后,NDIS 將調用下一個基礎驅動程序的請求函數。
若要同步完成, NdisOidRequest 將返回NDIS_STATUS_SUCCESS或錯誤狀態。 為了異步完成, NdisOidRequest 返回NDIS_STATUS_PENDING。
如果 NdisOidRequest 返回NDIS_STATUS_PENDING,則 NDIS 在基礎驅動程序完成 OID 請求后調用 ProtocolOidRequestComplete 函數。 在這種情況下,NDIS 在 ProtocolOidRequestComplete 的 OidRequest 參數中傳遞請求的結果。 NDIS 在 ProtocolOidRequestComplete 的 Status 參數中傳遞請求的最終狀態。
如果 NdisOidRequest 返回NDIS_STATUS_SUCCESS,它將在 OidRequest 參數的 NDIS_OID_REQUEST 結構中返回查詢請求的結果。 在這種情況下,NDIS 不調用 ProtocolOidRequestComplete 函數。
若要確定基礎驅動程序成功處理了哪些信息,發出 OID 請求的協議驅動程序必須在 OID 請求返回后檢查NDIS_OID_REQUEST結構中的 SupportedRevision 成員中的值。
如果基礎驅動程序應將 OID 請求與后續狀態指示相關聯,則協議驅動程序應在NDIS_OID_REQUEST結構中設置 RequestId 成員。 當基礎驅動程序發出狀態指示時,它會將 NDIS_STATUS_INDICATION 結構中的 RequestId 成員設置為 OID 請求中提供的值。
當綁定處于“正在重啟”、“正在運行”、“暫停”或“已暫停”狀態時,驅動程序可以調用 NdisOidRequest。
協議驅動程序直接 OID 請求
為了支持直接 OID 請求路徑,協議驅動程序在 NDIS_PROTOCOL_DRIVER_CHARACTERISTICS 結構中提供 ProtocolXxx 函數入口點,NDIS 為協議驅動程序提供 NdisXxx 函數。
直接 OID 請求接口類似于標準 OID 請求接口。 例如, NdisDirectOidRequest 和 ProtocolDirectOidRequestComplete 函數類似于 NdisOidRequest 和 ProtocolOidRequestComplete 函數。
注意 NDIS 6.1 及更高版本支持用于直接 OID 請求接口的特定 OID。 不支持在 NDIS 6.1 和某些 NDIS 6.1 OID 之前存在的 OID。
協議驅動程序同步 OID 請求
為了支持同步 OID 請求路徑,協議驅動程序調用 NdisSynchronousOidRequest 函數來發出同步 OID。
對于協議驅動程序, 同步 OID 請求接口 不同于常規和直接 OID 請求接口,即協議驅動程序不必實現異步 完整 回調函數,這是因為路徑的同步性質。
處理協議驅動程序中的狀態指示
協議驅動程序必須提供當基礎驅動程序報告狀態時 NDIS 調用的 ProtocolStatusEx 函數。
在基礎驅動程序 (NdisMIndicateStatus 或 NdisFIndicateStatus) 調用狀態指示函數后,NDIS 調用協議驅動程序的 ProtocolStatusEx 函數。?
如果狀態指示與 OID 請求相關聯,則基礎驅動程序可以設置 DestinationHandle 和 RequestId 成員,以便 NDIS 可以為特定協議綁定提供狀態指示。?
處理協議驅動程序中的 PnP 事件通知
除了特定于 NDIS 6.0 及更高版本的事件通知外,NDIS 6.0 及更高版本的協議驅動程序還處理與 NDIS 5.x 驅動程序相同的即插即用 (PnP) 事件通知。 PnP 事件通知的處理特定于驅動程序。
為了通知協議驅動程序網絡 PnP 事件,NDIS 調用驅動程序的 ProtocolNetPnPEvent 函數。 為了定義事件的類型和事件特征,NDIS 在 ProtocolNetPnPEvent 的 NetPnPEvent 事件參數中傳遞NET_PNP_EVENT_NOTIFICATION結構。
協議驅動程序應處理驅動程序堆棧更改。?不處理堆棧更改通知的協議驅動程序將從適配器取消綁定并反彈。 成功處理驅動程序堆棧通知的協議驅動程序綁定不受影響。
協議驅動程序中的可分頁和可丟棄代碼
驅動程序開發人員應盡可能將代碼指定為可分頁代碼,為必須駐留在內存中的代碼釋放系統空間。 可以使用 NDIS_PAGEABLE_FUNCTION 宏將函數標記為可分頁。 函數的 IRQL、資源管理功能和其他特征可能會禁止該函數可分頁。
每個 ProtocolXxx 函數在 IRQL 上運行,范圍從 PASSIVE_LEVEL 到 DISPATCH_LEVEL。 以 IRQL = PASSIVE_LEVEL 獨占方式運行的函數應標記為可分頁。
只要在 IRQL = PASSIVE_LEVEL 上運行的驅動程序函數既不調用也不由在 IRQL >= DISPATCH_LEVEL運行的任何函數(例如獲取旋轉鎖的函數)調用,就可以使該函數可分頁。 獲取旋轉鎖會導致獲取線程的 IRQL 提升為DISPATCH_LEVEL。 在 IRQL = PASSIVE_LEVEL運行的驅動程序函數(如 ProtocolBindAdapterEx)不得調用在 IRQL >= DISPATCH_LEVEL下運行的任何 NdisXxx 函數(如果該驅動程序函數被標記為可分頁代碼)。 有關每個 NdisXxx 函數的 IRQL 的詳細信息,請參閱 NDIS 庫函數。
應使用 NDIS_INIT_FUNCTION 宏將 NDIS 協議驅動程序的 DriverEntry 函數以及僅從 DriverEntry 調用 的代碼 指定為僅初始化代碼。 假定使用此宏標識的代碼在系統初始化時只運行一次,因此,僅在該時間內映射代碼。 在標記為“僅初始化”的函數返回后,該函數將被丟棄。
協議驅動程序重置操作
協議驅動程序無法在 NDIS 6.0 及更高版本中啟動重置操作。
通常,基礎微型端口驅動程序會重置 NIC,因為 NIC 在發送或請求操作期間超時。 此條件導致 NDIS 調用微型端口驅動程序的 MiniportCheckForHangEx 和隨后 的 MiniportResetEx 函數。 或者,微型端口驅動程序確定 NIC 的接收功能功能失調。
如果重置由 NDIS 啟動, 并且 MiniportResetEx 返回NDIS_STATUS_PENDING,則 NDIS 調用每個綁定協議驅動程序的 ProtocolStatusEx (或 ProtocolCoStatusEx) 函數,其狀態為 NDIS_STATUS_RESET_START。 當微型端口驅動程序調用 NdisMResetComplete 時,NDIS 會再次調用 ProtocolStatusEx (或 ProtocolCoStatusEx) ,其狀態為 NDIS_STATUS_RESET_END。
協議驅動程序必須處理在綁定到基礎 NIC 上的未完成發送可以取消的可能性,因為 NIC 已重置。 如果綁定的協議驅動程序有任何掛起的傳輸請求,NDIS 將指示以適當的狀態向協議驅動程序發送完成。 當重置操作完成后,協議驅動程序必須重新提交發送請求,前提是 NIC 再次正常運行。
當協議驅動程序收到NDIS_STATUS_RESET_START狀態時,它應:
保留已準備好傳輸的任何網絡數據 ,直到協議 Status 收到NDIS_STATUS_RESET_END通知。
不進行任何定向到基礎微型端口驅動程序的 NDIS 調用,但返回資源(如使用 NdisReturnNetBufferLists 返回網絡數據)的調用除外。
ProtocolStatusEx (或 ProtocolCoStatusEx) 收到NDIS_STATUS_RESET_END消息后,協議驅動程序可以繼續發送網絡數據和 OID 請求。
處理協議驅動程序中的 PnP 事件和電源管理事件
當操作系統向表示網絡接口卡 (NIC) 的目標設備對象發出即插即用 (PnP) I/O 請求數據包 (IRP) 或電源管理 IRP 時,NDIS 會截獲該 IRP。 NDIS 通過調用驅動程序的 ProtocolNetPnPEvent 函數,向每個綁定協議驅動程序和每個綁定中間驅動程序指示事件。 在對 ProtocolNetPnPEvent 的調用中,NDIS 傳遞指向包含NET_PNP_EVENT結構的 NET_PNP_EVENT_NOTIFICATION 的指針。 NET_PNP_EVENT結構描述要指示的 PnP 事件或電源管理事件。 有關協議驅動程序 PnP 接口的詳細信息,請參閱 處理協議驅動程序中的 PnP 事件通知。
以下列表包含 PnP 和電源管理事件,如 NET_PNP_EVENT 結構中的 NetEvent 代碼所示:
NetEventSetPower: 指示設置電源請求,該請求指定微型端口適配器應轉換為特定電源狀態。 電源管理感知協議驅動程序應始終通過返回NDIS_STATUS_SUCCESS成功此事件。 舊的協議驅動程序可以返回NDIS_STATUS_NOT_SUPPORTED,以指示 NDIS 應將其與微型端口適配器取消綁定。
發出設置電源請求后,如果微型端口適配器正在轉換為低功耗狀態,NDIS 將暫停驅動程序堆棧。 如果微型端口適配器正在轉換為工作狀態 (D0) ,則在設置電源請求之前,NDIS 會重啟驅動程序堆棧。?
如果微型端口適配器處于低功耗狀態,則協議驅動程序無法發出任何 OID 請求。 此要求是額外的電源管理限制,在驅動程序堆棧處于“已暫停”狀態時,將添加到其他限制中。
如果基礎微型端口適配器無法識別電源管理,微型端口驅動程序會將NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES的 PowerManagementCapabilities 成員設置為 NULL,NDIS 將 NDIS_BIND_PARAMETERS 的 PowerManagementCapabilities 成員設置為 NULL。
注意 從 NDIS 6.30 開始,在收到此事件的通知后,協議驅動程序必須停止生成新的 I/O 請求,并且不應等待調用 ProtocolNetPnPEvent 的上下文中任何掛起的 I/O 請求完成。
NetEventQueryPower:指示查詢電源請求,該請求查詢基礎微型端口適配器是否可以轉換到特定電源狀態。 協議驅動程序應始終成功 NetEventQueryPower 。 建立活動連接后,協議驅動程序可以調用 PoRegisterSystemState 來注冊連續忙狀態。 只要狀態注冊生效,電源管理器就不會嘗試使系統進入睡眠狀態。 連接變為非活動狀態后,協議驅動程序通過調用 PoUnregisterSystemState 取消狀態注冊。 協議驅動程序絕不應嘗試通過使 NetEventQueryRemoveDevice 失敗來阻止系統轉換到睡眠狀態。 請注意, NetEventQueryPower 始終后跟 NetEventSetPower。 設置設備當前電源狀態的 NetEventSetPower 將取消 NetEventQueryPower。
注意 從 NDIS 6.30 開始,在收到此事件的通知后,協議驅動程序不應在調用 ProtocolNetPnPEvent 的上下文中等待任何掛起的 I/O 請求完成。
NetEventQueryRemoveDevice:指示查詢刪除設備請求,該請求查詢是否可以在不中斷操作的情況下刪除 NIC。 例如,如果協議驅動程序無法釋放設備 (因為設備正在使用) ,則必須通過返回NDIS_STATUS_FAILURE來使 NetEventQueryRemoveDevice 失敗。
NetEventCancelRemoveDevice:指示取消刪除設備請求,該請求取消刪除基礎 NIC。 協議驅動程序應始終通過返回NDIS_STATUS_SUCCESS成功此事件。
NetEventReconfigure:指示網絡組件的配置已更改。 例如,如果用戶更改 TCP/IP 的 IP 地址,NDIS 會使用 NetEventReconfigure 代碼向 TCP/IP 協議指示此事件。 在極少數情況下,如果協議驅動程序無法應用指示的配置更改并且沒有可用的默認值,則可能會返回失敗代碼。 分配內存的失敗嘗試是協議返回失敗代碼的一個示例。 返回錯誤代碼可能會導致提示用戶重啟系統。協議應驗證傳遞給其 ProtocolNetPnPEvent 函數的 NetEventReconfigure 相關數據。?
NetEventBindList:向協議驅動程序指示其綁定列表處理順序已重新配置。 此列表指示在處理時應用于協議綁定的相對順序,例如,可能路由到多個綁定之一的用戶請求。 隨此事件一起傳遞的緩沖區包含以 NULL 結尾的 Unicode 字符串格式的設備名稱列表。 每個設備名稱的格式與傳遞給 ProtocolBindAdapterEx 調用的 DeviceName 參數相同。協議應驗證傳遞給其 ProtocolNetPnPEvent 函數的 NetEventBindList 相關數據;協議應驗證傳遞給其 ProtocolNetPnPEvent 函數的 NetEventBindList 相關數據。?
NetEventBindsComplete:指示協議驅動程序已綁定到它可以綁定到的所有 NIC。 除非將 PnP NIC 插入系統,否則 NDIS 不會指示與協議驅動程序的更多綁定。
NetEventPnPCapabilities:指示用戶啟用或禁用基礎適配器的喚醒功能。 NDIS 傳遞給 ProtocolNetPnPEvent 的 ProtocolBindingContext 參數指定綁定。
NetEventPause:指示指定的協議綁定應進入暫停狀態。 NDIS 完成綁定的所有未完成發送請求后,綁定將進入“已暫停”狀態。
NetEventRestart:指示指定的協議綁定已進入“正在重啟”狀態。 協議驅動程序準備好恢復綁定的發送和接收操作后,綁定將進入“正在運行”狀態。?
NetEventPortActivation: 指示激活與指定綁定關聯的端口列表。?
NetEventPortDeactivation:指示停用與指定綁定關聯的端口列表。?
NetEventIMReEnableDevice:指示已更改 NDIS 6.0 或更高版本中間驅動程序的虛擬微型端口的配置。 NetEventIMReEnableDevice 類似于 NetEventReconfigure 事件,不同之處在于中間驅動程序接收單個虛擬微型端口的此事件, NetEventReconfigure 事件應用于所有中間驅動程序的虛擬微型端口。 例如,當用戶禁用然后從設備管理器或其他源啟用單個虛擬微型端口時,中間驅動程序會收到 NetEventIMReEnableDevice 事件。
NET_PNP_EVENT 結構的 Buffer 成員指向包含特定于所指示事件的信息的緩沖區。
協議驅動程序可以使用 NdisCompleteNetPnPEvent 異步完成對 ProtocolNetPnPEvent 的調用。