void CParaNdisTX::CancelNBLs(PVOID CancelId) { auto CanceledNBLs = BuildCancelList(CancelId); if (CanceledNBLs != nullptr) { NdisMSendNetBufferListsComplete(m_Context->MiniportHandle, CanceledNBLs, 0); } }
VOID NicDropPacket(IN PMP_ADAPTER Adapter, IN PNDIS_PACKET_OR_NBL pNBSPacket) { NET_BUFFER_LIST_STATUS(pNBSPacket) = NDIS_STATUS_FAILURE; NdisMSendNetBufferListsComplete(Adapter->AdapterHandle, pNBSPacket, 0); InterlockedIncrement64(&Adapter->ullTransmitFail); }
VOID NicCompletePacket(IN PMP_ADAPTER Adapter, IN PNDIS_PACKET_OR_NBL pNBSPacket) { NET_BUFFER_LIST_STATUS(pNBSPacket) = NDIS_STATUS_SUCCESS; NdisMSendNetBufferListsComplete(Adapter->AdapterHandle, pNBSPacket, 0); InterlockedIncrement64(&Adapter->ullGoodTransmits); }
bool CParaNdisTX::DoPendingTasks(bool IsInterrupt) { ONPAUSECOMPLETEPROC CallbackToCall = nullptr; PNET_BUFFER_LIST pNBLFailNow = nullptr; PNET_BUFFER_LIST pNBLReturnNow = nullptr; bool bDoKick = false; DoWithTXLock([&] () { m_VirtQueue.ProcessTXCompletions(); bDoKick = SendMapped(IsInterrupt, pNBLFailNow); pNBLReturnNow = ProcessWaitingList(); if (!m_VirtQueue.HasPacketsInHW() && m_Context->SendState == srsPausing) { CallbackToCall = m_Context->SendPauseCompletionProc; m_Context->SendPauseCompletionProc = nullptr; m_Context->SendState = srsDisabled; } }); if (pNBLFailNow) { NdisMSendNetBufferListsComplete(m_Context->MiniportHandle, pNBLFailNow, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); } if (pNBLReturnNow) { NdisMSendNetBufferListsComplete(m_Context->MiniportHandle, pNBLReturnNow, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL); } if (CallbackToCall != nullptr) { CallbackToCall(m_Context); } return bDoKick; }
// Stop check of packet transmission BOOL NeoNdisSendPacketsHaltCheck(NET_BUFFER_LIST *NetBufferLists) { if (ctx == NULL) { return FALSE; } if (ctx->Halting != FALSE || ctx->Opened == FALSE) { // Halting NdisMSendNetBufferListsComplete(ctx->NdisMiniport, NetBufferLists, NDIS_STATUS_FAILURE); return FALSE; } return TRUE; }
CNBL::~CNBL() { CDpcIrqlRaiser OnDpc; m_MappedBuffers.ForEachDetached([this](CNB *NB) { CNB::Destroy(NB, m_Context->MiniportHandle); }); m_Buffers.ForEachDetached([this](CNB *NB) { CNB::Destroy(NB, m_Context->MiniportHandle); }); if(m_NBL) { auto NBL = DetachInternalObject(); NET_BUFFER_LIST_NEXT_NBL(NBL) = nullptr; NdisMSendNetBufferListsComplete(m_Context->MiniportHandle, NBL, 0); } }
VOID TXNblRelease( _In_ PMP_ADAPTER Adapter, _In_ PNET_BUFFER_LIST NetBufferList, _In_ BOOLEAN fAtDispatch) /*++ Routine Description: Releases a reference on a NBL that is being transmitted. If the last reference is released, the NBL is returned to the protocol. Runs at IRQL <= DISPATCH_LEVEL. Arguments: Adapter Pointer to our adapter NetBufferList The NBL to release fAtDispatch TRUE if the current IRQL is DISPATCH_LEVEL Return Value: None. --*/ { if (0 == NdisInterlockedDecrement(&SEND_REF_FROM_NBL(NetBufferList))) { DEBUGP(MP_TRACE, "[%p] Send NBL %p complete.\n", Adapter, NetBufferList); NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL; NdisMSendNetBufferListsComplete( Adapter->AdapterHandle, NetBufferList, fAtDispatch ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0); } else { DEBUGP(MP_TRACE, "[%p] Send NBL %p not complete. RefCount: %i.\n", Adapter, NetBufferList, SEND_REF_FROM_NBL(NetBufferList)); } NdisInterlockedDecrement(&Adapter->nBusySend); }
bool CParaNdisTX::Pause() { PNET_BUFFER_LIST NBL = nullptr; bool res; DoWithTXLock([this, &NBL, &res]() { NBL = RemoveAllNonWaitingNBLs(); res = (!m_VirtQueue.HasPacketsInHW() && m_WaitingList.IsEmpty()); }); if(NBL != nullptr) { NdisMSendNetBufferListsComplete(m_Context->MiniportHandle, NBL, 0); } return res; }
VOID MPSendNetBufferLists( NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST NetBufferLists, NDIS_PORT_NUMBER PortNumber, ULONG SendFlags ) { PADAPTER adapter = (PADAPTER)MiniportAdapterContext; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PMP_PORT destinationPort = NULL; PNET_BUFFER_LIST currentNetBufferList; // // We increment the port list refcount. This would avoid a pause from finishing // while we are processing this NBL and that ensures that the port list does not // change // MP_INCREMENT_PORTLIST_REFCOUNT(adapter); do { // // If the adapter is paused, surprise removed, etc, fail the send // if (MP_TEST_ADAPTER_STATUS(adapter, MP_ADAPTER_CANNOT_SEND_MASK)) { ndisStatus = MpGetAdapterStatus(adapter); MpTrace(COMP_SEND, DBG_NORMAL, ("Sends failed as adapter is not in a valid send state\n")); break; } // // First we would need to translate from the NDIS_PORT_NUMBER // to our port structure. This is done by walking the PortList // destinationPort = Port11TranslatePortNumberToPort( adapter, PortNumber ); if (destinationPort == NULL) { MpTrace(COMP_SEND, DBG_SERIOUS, ("Unable to find Port corresponding to PortNumber %d\n", PortNumber)); ndisStatus = NDIS_STATUS_INVALID_PORT; } else { // // Pass it to the appropriate port for processing // Port11HandleSendNetBufferLists( destinationPort, NetBufferLists, SendFlags ); } } while (FALSE); // // We were protecting the port list only until we hand it to the port. After this point, the port // is responsible for ensuring that it does not let the port get deleted while // it has packets pending on it // MP_DECREMENT_PORTLIST_REFCOUNT(adapter); if (ndisStatus != NDIS_STATUS_SUCCESS) { #if DBG ULONG ulNumFailedNBLs = 0; #endif // // Send failed. Complete the NBLs back to NDIS // for(currentNetBufferList = NetBufferLists; currentNetBufferList != NULL; currentNetBufferList = NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList)) { #if DBG ulNumFailedNBLs++; #endif NET_BUFFER_LIST_STATUS(currentNetBufferList) = ndisStatus; } #if DBG MpTrace(COMP_SEND, DBG_NORMAL, ("NdisMSendNetBufferListsComplete called with %d NBLs\n", ulNumFailedNBLs)); #endif if (NetBufferLists != NULL) { NdisMSendNetBufferListsComplete( adapter->MiniportAdapterHandle, NetBufferLists, (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0) ); } } }
VOID BasePortCompleteFailedPackets( __in PMP_PORT Port, __in PMP_TX_MSDU PacketList, __in ULONG SendCompleteFlags ) { PMP_TX_MSDU currentPacket = PacketList; PNET_BUFFER_LIST currentNetBufferList, prevNetBufferList = NULL; PNET_BUFFER_LIST netBufferListsToComplete = NULL; #if DBG ULONG ulNumNBLs = 0, ulInternalSends = 0; #endif while (currentPacket != NULL) { // // No refcount is added yet, so we dont need to remove anything // if (MP_TX_MSDU_WRAPPED_NBL(currentPacket) == NULL) { #if DBG ulInternalSends++; #endif // Internal packet submitted from BasePortSendInternalPacket, free the memory // we allocated for the buffer MP_FREE_MEMORY(MP_TX_MSDU_MPDU_AT(currentPacket, 0)->InternalSendBuffer); } else { #if DBG ulNumNBLs++; #endif // // There were from the OS. We need to convert back to NBLs and // complete them to the OS // // // Get the NBLs out // currentNetBufferList = currentPacket->NetBufferList; NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList) = NULL; NET_BUFFER_LIST_STATUS(currentNetBufferList) = currentPacket->Status; if (netBufferListsToComplete == NULL) { netBufferListsToComplete = currentNetBufferList; } else { NET_BUFFER_LIST_NEXT_NBL(prevNetBufferList) = currentNetBufferList; } prevNetBufferList = currentNetBufferList; } currentPacket = MP_TX_MSDU_NEXT_MSDU(currentPacket); } // // Free our packet wrapper structures for all the packets // BasePortFreeTranslatedTxPackets(Port, PacketList); #if DBG MpTrace(COMP_SEND, DBG_NORMAL, ("Port(%d): NdisMSendNetBufferListsComplete called with %d NBLs\n", Port->PortNumber, ulNumNBLs)); MpTrace(COMP_SEND, DBG_NORMAL, ("Port(%d): Completed %d internal sends\n", Port->PortNumber, ulInternalSends)); #endif if (netBufferListsToComplete != NULL) { // Complete the NBLs back to NDIS NdisMSendNetBufferListsComplete( Port->MiniportAdapterHandle, netBufferListsToComplete, SendCompleteFlags ); } }
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); }
// Packet send handler void NeoNdisSendNetBufferLists(NDIS_HANDLE MiniportAdapterContext, NET_BUFFER_LIST *NetBufferLists, NDIS_PORT_NUMBER PortNumber, ULONG SendFlags) { if (ctx == NULL) { return; } // Update the connection state NeoCheckConnectState(); if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE) { // Device is stopped return; } // Operation of the packet queue NeoLockPacketQueue(); { NET_BUFFER_LIST *nbl; if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE) { // Device is stopped NeoUnlockPacketQueue(); return; } nbl = NetBufferLists; while (nbl != NULL) { NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); while (nb != NULL) { UINT size = NET_BUFFER_DATA_LENGTH(nb); if (size >= NEO_MIN_PACKET_SIZE && size <= NEO_MAX_PACKET_SIZE) { UCHAR *buf = NeoMalloc(size); void *ptr; ptr = NdisGetDataBuffer(nb, size, buf, 1, 0); if (ptr == NULL) { ctx->Status.NumPacketSendError++; ctx->Status.Int64NumSendError++; NeoFree(buf); } else { if (ptr != buf) { NeoCopy(buf, ptr, size); } NeoInsertQueue(buf, size); ctx->Status.NumPacketSend++; if (buf[0] & 0x40) { ctx->Status.Int64NumSendBroadcast++; ctx->Status.Int64BytesSendBroadcast += (UINT64)size; } else { ctx->Status.Int64NumSendUnicast++; ctx->Status.Int64BytesSendUnicast += (UINT64)size; } ctx->Status.Int64BytesSendTotal += (UINT64)size; } } else { ctx->Status.NumPacketSendError++; ctx->Status.Int64NumSendError++; } nb = NET_BUFFER_NEXT_NB(nb); } nbl = NET_BUFFER_LIST_NEXT_NBL(nbl); } } NeoUnlockPacketQueue(); // Notify the transmission completion NdisMSendNetBufferListsComplete(ctx->NdisMiniport, NetBufferLists, NDIS_STATUS_SUCCESS); // Reception event NeoSet(ctx->Event); }