VOID ReturnTCB( __in PMP_ADAPTER Adapter, __in PTCB Tcb) { TXNblRelease(Adapter, NBL_FROM_SEND_NB(Tcb->NetBuffer), TRUE); Tcb->NetBuffer = NULL; NdisInterlockedInsertTailList( &Adapter->FreeTcbList, &Tcb->TcbLink, &Adapter->FreeTcbListLock); }
VOID MPSendNetBufferLists( _In_ NDIS_HANDLE MiniportAdapterContext, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ NDIS_PORT_NUMBER PortNumber, _In_ ULONG SendFlags) /*++ Routine Description: Send Packet Array handler. Called by NDIS whenever a protocol bound to our miniport sends one or more packets. The input packet descriptor pointers have been ordered according to the order in which the packets should be sent over the network by the protocol driver that set up the packet array. The NDIS library preserves the protocol-determined ordering when it submits each packet array to MiniportSendPackets As a deserialized driver, we are responsible for holding incoming send packets in our internal queue until they can be transmitted over the network and for preserving the protocol-determined ordering of packet descriptors incoming to its MiniportSendPackets function. A deserialized miniport driver must complete each incoming send packet with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable. Runs at IRQL <= DISPATCH_LEVEL Arguments: MiniportAdapterContext Pointer to our adapter NetBufferLists Head of a list of NBLs to send PortNumber A miniport adapter port. Default is 0. SendFlags Additional flags for the send operation Return Value: None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS macro. --*/ { PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext); PNET_BUFFER_LIST Nbl; PNET_BUFFER_LIST NextNbl = NULL; BOOLEAN fAtDispatch = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL) ? TRUE:FALSE; NDIS_STATUS Status; ULONG NumNbls=0; DEBUGP(MP_TRACE, "[%p] ---> MPSendNetBufferLists\n", Adapter); UNREFERENCED_PARAMETER(PortNumber); UNREFERENCED_PARAMETER(SendFlags); ASSERT(PortNumber == 0); // Only the default port is supported // // Each NET_BUFFER_LIST has a list of NET_BUFFERs. // Loop over all the NET_BUFFER_LISTs, sending each NET_BUFFER. // for ( Nbl = NetBufferLists; Nbl!= NULL; Nbl = NextNbl, ++NumNbls) { PNET_BUFFER NetBuffer; NextNbl = NET_BUFFER_LIST_NEXT_NBL(Nbl); // // Unlink the NBL and prepare our bookkeeping. // // We use a reference count to make sure that we don't send complete // the NBL until we're done reading each NB on the NBL. // NET_BUFFER_LIST_NEXT_NBL(Nbl) = NULL; SEND_REF_FROM_NBL(Nbl) = 0; Status = TXNblReference(Adapter, Nbl); if(Status == NDIS_STATUS_SUCCESS) { NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_SUCCESS; // // Queue each NB for transmission. // for ( NetBuffer = NET_BUFFER_LIST_FIRST_NB(Nbl); NetBuffer != NULL; NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer)) { NBL_FROM_SEND_NB(NetBuffer) = Nbl; TXQueueNetBufferForSend(Adapter, NetBuffer); } TXNblRelease(Adapter, Nbl, fAtDispatch); } else { // // We can't send this NBL now. Indicate failure. // if (MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS)) { NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_RESET_IN_PROGRESS; } else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS|fMP_ADAPTER_PAUSED)) { NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_PAUSED; } else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LOW_POWER)) { NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_LOW_POWER_STATE; } else { NET_BUFFER_LIST_STATUS(Nbl) = Status; } NdisMSendNetBufferListsComplete( Adapter->AdapterHandle, Nbl, fAtDispatch ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0); continue; } } DEBUGP(MP_TRACE, "[%p] %i NBLs processed.\n", Adapter, NumNbls); // // Now actually go send each of the queued NBs. // TXTransmitQueuedSends(Adapter, fAtDispatch); DEBUGP(MP_TRACE, "[%p] <--- MPSendNetBufferLists\n", Adapter); }
VOID TXFlushSendQueue( _In_ PMP_ADAPTER Adapter, _In_ NDIS_STATUS CompleteStatus) /*++ Routine Description: This routine is called by the Halt or Reset handler to fail all the queued up Send NBLs because the device is either gone, being stopped for resource rebalance, or reset. Arguments: Adapter Pointer to our adapter CompleteStatus The status code with which to complete each NBL Return Value: None. --*/ { PTCB Tcb; DEBUGP(MP_TRACE, "[%p] ---> TXFlushSendQueue Status = 0x%08x\n", Adapter, CompleteStatus); // // First, free anything queued in the driver. // while (TRUE) { PLIST_ENTRY pEntry; PNET_BUFFER NetBuffer; PNET_BUFFER_LIST NetBufferList; pEntry = NdisInterlockedRemoveHeadList( &Adapter->SendWaitList, &Adapter->SendWaitListLock); if (!pEntry) { // End of list -- nothing left to free. break; } NetBuffer = NB_FROM_SEND_WAIT_LIST(pEntry); NetBufferList = NBL_FROM_SEND_NB(NetBuffer); DEBUGP(MP_TRACE, "[%p] Dropping Send NB: 0x%p.\n", Adapter, NetBuffer); NET_BUFFER_LIST_STATUS(NetBufferList) = CompleteStatus; TXNblRelease(Adapter, NetBufferList, FALSE); } // // Next, cancel anything queued in the hardware. // while (NULL != (Tcb = TXGetNextTcbToSend(Adapter))) { NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(Tcb->NetBuffer)) = CompleteStatus; ReturnTCB(Adapter, Tcb); } DEBUGP(MP_TRACE, "[%p] <--- TXFlushSendQueue\n", Adapter); }