Canceling a Send Operation
The following figure illustrates canceling a send operation.
A driver calls the NDIS_SET_NET_BUFFER_LIST_CANCEL_ID macro for each NET_BUFFER_LIST structure that it passes to lower-level drivers for transmission. The NDIS_SET_NET_BUFFER_LIST_CANCEL_ID function marks the specified packet with a cancellation identifier.
Before assigning cancellation IDs to packets, a driver should call NdisGeneratePartialCancelId to obtain the high-order byte of each cancellation ID that it assigns. This ensures that the driver does not duplicate cancellation IDs assigned by other drivers in the system. Drivers typically call NdisGeneratePartialCancelId once from the DriverEntry routine; however, drivers can obtain more than one partial cancellation identifier by calling NdisGeneratePartialCancelId more than once.
To cancel the pending transmission of data in a marked NET_BUFFER_LIST structure, a driver passes the cancellation ID to the NdisCancelSendNetBufferLists function. Drivers can obtain a NET_BUFFER_LIST structure's cancellation ID by calling the NDIS_GET_NET_BUFFER_LIST_CANCEL_ID macro.
If a driver marks all NET_BUFFER_LIST structures with the same cancellation identifier, it can cancel all pending transmissions with a single call to NdisCancelSendNetBufferLists. If a driver marks all NET_BUFFER_LIST structures within a subgroup of NET_BUFFER_LIST structures with a unique identifier, it can cancel all pending transmissions within that subgroup with a single call to NdisCancelSendNetBufferLists.
NDIS calls the MiniportCancelSend function of the appropriate lower-level driver on the binding. After aborting the pending transmission, the underlying miniport driver calls the NdisMSendNetBufferListsComplete function, to return the NET_BUFFER_LIST structures and a completion status of NDIS_STATUS_SEND_ABORTED. NDIS, in turn, calls the appropriate driver's ProtocolSendNetBufferListsComplete function.
In its ProtocolSendNetBufferListsComplete function, a protocol driver can call NDIS_SET_NET_BUFFER_LIST_CANCEL_ID with CancelId set to NULL. This prevents the NET_BUFFER_LIST from inadvertently being used again with a stale cancellation ID.