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); }
/* SdrLLSendPacketComplete cleans resouces occupied by SdrLLSendPacket. History: 3/Nov/2009: Created by senxiang Note: Different SdrLLSendPacket implementation needs different complete handler. */ VOID SdrLLSendPacketComplete( PSDR_CONTEXT SDRContext, PDLCB pDLCB) { PSEND_QUEUE_MANAGER pSendQueueManager = GET_SEND_QUEUE_MANAGER((PMAC)SDRContext->Mac); if (DLCB_CONTAIN_VALID_PACKET(pDLCB)) { CleanWLanPacket( pDLCB->pDot11HeaderVa, pDLCB->Dot11HeaderSize, pDLCB->PacketBase.pMdl); //cleanup resources in EthToWlan. } pDLCB->pDot11HeaderVa = NULL; pDLCB->PacketBase.pMdl = NULL; if(pDLCB->pNdisPktOrNBL) { //One NB fail the whole NBL fail if(pDLCB->bSendOK == FALSE) { NET_BUFFER_LIST_STATUS((PNET_BUFFER_LIST)(pDLCB->pNdisPktOrNBL)) = NDIS_STATUS_FAILURE; } //If it's the last NB if(pDLCB->bLastNB) { if(NET_BUFFER_LIST_STATUS((PNET_BUFFER_LIST)(pDLCB->pNdisPktOrNBL)) == NDIS_STATUS_SUCCESS) { NicCompletePacket((PMP_ADAPTER)SDRContext->Nic, (PNET_BUFFER_LIST)(pDLCB->pNdisPktOrNBL)); } else { NicDropPacket((PMP_ADAPTER)SDRContext->Nic, (PNET_BUFFER_LIST)(pDLCB->pNdisPktOrNBL)); } } //clear pDLCB->pNdisPktOrNBL = NULL; } SoraPacketCleanup (&pDLCB->PacketBase); SafeEnqueue(pSendQueueManager, SendFreeList, pDLCB); InterlockedIncrement(&pSendQueueManager->nFreeTCB); }
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 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 NdisprotSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_BUFFER_LIST pNetBufferList, IN ULONG SendCompleteFlags ) /*++ Routine Description: NDIS entry point called to signify completion of a packet send. We pick up and complete the Write IRP corresponding to this packet. Arguments: ProtocolBindingContext - pointer to open context pNetBufferList - NetBufferList that completed send SendCompleteFlags - Specifies if the caller is at DISPATCH level Return Value: None --*/ { PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST CurrNetBufferList = NULL; PNET_BUFFER_LIST NextNetBufferList; NDIS_STATUS CompletionStatus; BOOLEAN DispatchLevel; WDFREQUEST request; PREQUEST_CONTEXT reqContext; pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext; NPROT_STRUCT_ASSERT(pOpenContext, oc); DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags); for (CurrNetBufferList = pNetBufferList; CurrNetBufferList != NULL; CurrNetBufferList = NextNetBufferList) { NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList); request = NPROT_REQUEST_FROM_SEND_NBL(CurrNetBufferList); reqContext = GetRequestContext(request); CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList); DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d " "completed with status %x\n", CurrNetBufferList, request, reqContext->Length, CompletionStatus)); // // We are done with the NDIS_PACKET: // NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel); CurrNetBufferList = NULL; if (CompletionStatus == NDIS_STATUS_SUCCESS) { WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, reqContext->Length); } else { WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); pOpenContext->PendedSendCount--; if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING)) && (pOpenContext->PendedSendCount == 0)) { NPROT_ASSERT(pOpenContext->ClosingEvent != NULL); NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent); pOpenContext->ClosingEvent = NULL; } NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP } }
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 FilterSendNetBufferLists( IN NDIS_HANDLE FilterModuleContext, IN PNET_BUFFER_LIST NetBufferLists, IN NDIS_PORT_NUMBER PortNumber, IN ULONG SendFlags ) /*++ Routine Description: Send Net Buffer List handler This function is an optional function for filter drivers. If provided, NDIS will call this function to transmit a linked list of NetBuffers, described by a NetBuferList, over the network. If this handler is NULL, NDIS will skip calling this fitler when sending a NetBufferList and will call the next lower fitler in the stack with a non_NULL FilterSendNetBufferList handleror the miniport driver. A filter that doesn't provide a FilerSendNetBufferList handler can not initiate a send o its own. Arguments: FilterModuleContext: Pointer to our filter context area. NetBufferLists: Pointer to a List of NetBufferLists. PortNumber - Port Number to which this send is targetted SendFlags- Specifies if the call is at DISPATCH_LEVEL Return Value: NDIS_STATUS_SUCCESS: NDIS_STATUS_PENDING: NDIS_STATUS_INVALID_PACKET: NDIS_STATUS_RESOURCES: NDIS_STATUS_FAILURE: NOTE: The filter will act like a passthru filter. --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PNET_BUFFER_LIST CurrNbl; BOOLEAN DispatchLevel; // ++ PNET_BUFFER_LIST CurrentBufferList = NULL; PNET_BUFFER CurrentBuffer = NULL; PNET_BUFFER_DATA CurrentBufferData = NULL; PMDL PacketMdl = NULL; ULONG DataOffset = 0; ULONG PacketSize = 0; PUCHAR PacketData = NULL; ARP_PACKET* ArpPacket = NULL; BOOLEAN bWanAdapter = FALSE; // -- DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists)); do { DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); #if DBG // // we should never get packets to send if we are not in running state // FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); // // If the filter is not in running state, fail the send // if (pFilter->State != FilterRunning) { FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); CurrNbl = NetBufferLists; while (CurrNbl) { NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED; CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); } NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0); break; } FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); #endif // ++ CurrentBufferList = NetBufferLists; while(CurrentBufferList) { // Each NET_BUFFER structure packages a packet of network data CurrentBuffer = NET_BUFFER_LIST_FIRST_NB(CurrentBufferList); while(CurrentBuffer) { // 检测其中是否有ARP协议包 PacketMdl = NET_BUFFER_FIRST_MDL(CurrentBuffer); DataOffset = NET_BUFFER_DATA_OFFSET(CurrentBuffer); PacketSize = NET_BUFFER_DATA_LENGTH(CurrentBuffer); if(PacketMdl && PacketSize) { PacketData = (UCHAR*)MmGetSystemAddressForMdlSafe(PacketMdl,NormalPagePriority); if(PacketData) { if(DataOffset) { PacketData = PacketData + DataOffset; } // PacketData 是网络包数据,PacketSize 是网络包数据长度 KdPrint((" PacketData : %p , PacketSize : %d ",PacketData,PacketSize)); ArpPacket = (ARP_PACKET*)PacketData; // 记录网关回应查询次数 NdisAcquireSpinLock(&GlobalLock); if( ArpPacket->EthType == ETHERNET_ARP) { if( g_bRecord_ARP_Reply && ArpPacket->OperateCode == ARP_QUERY && NdisEqualMemory(ArpPacket->DestIPAddress,g_Want_ARP_Reply_IP,4) ) { g_Reply_Record->ulQueryCount ++; //开始记录网关查询操作 BeginCheckGateway(); } } NdisReleaseSpinLock(&GlobalLock); } } CurrentBuffer = NET_BUFFER_NEXT_NB(CurrentBuffer); } CurrentBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrentBufferList); } // -- if (pFilter->TrackSends) { FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); CurrNbl = NetBufferLists; while (CurrNbl) { pFilter->OutstandingSends++; FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends); CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); } FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); } // // If necessary, queue the NetBufferList in a local structure for later processing // NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags); } while (FALSE); DEBUGP(DL_TRACE, ("<===SendNetBufferList: Status = %8x.\n", Status)); }
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); }
VOID TXSendComplete( _In_ PMP_ADAPTER Adapter) /*++ Routine Description: This routine completes pending sends for the given adapter. Each busy TCB is popped from the BusyTcbList and its corresponding NB is released. If there was an error sending the frame, the NB's NBL's status is updated. --*/ { BOOLEAN fRescheduleThisDpcAgain = TRUE; ULONG NumFramesSent = 0; DEBUGP(MP_TRACE, "[%p] ---> TXSendComplete.\n", Adapter); for (NumFramesSent = 0; NumFramesSent < NIC_MAX_SENDS_PER_DPC; NumFramesSent++) { ULONG BytesSent; PTCB Tcb = TXGetNextTcbToSend(Adapter); if (!Tcb) { // // There are no more TCBs remaining to send. We're all done. // fRescheduleThisDpcAgain = FALSE; break; } // // Finish the transmit operation. For our hardware, that means the // frame is pushed onto the RecvWaitLists of each other adapter. // BytesSent = HWGetBytesSent(Adapter, Tcb); if (BytesSent == 0) { // // Failed to send the frame. // Adapter->TransmitFailuresOther++; NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(Tcb->NetBuffer)) = NDIS_STATUS_RESOURCES; } else { // // We've finished sending this NB successfully; update the stats. // switch (Tcb->FrameType) { case NDIS_PACKET_TYPE_BROADCAST: Adapter->FramesTxBroadcast++; Adapter->BytesTxBroadcast += BytesSent; break; case NDIS_PACKET_TYPE_MULTICAST: Adapter->FramesTxMulticast++; Adapter->BytesTxMulticast += BytesSent; break; case NDIS_PACKET_TYPE_DIRECTED: default: Adapter->FramesTxDirected++; Adapter->BytesTxDirected += BytesSent; } } // // Now that we've finished using the TCB and its associated NET_BUFFER, // we can release the NET_BUFFER back to the protocol and the TCB back // to the free list. // ReturnTCB(Adapter, Tcb); } TXTransmitQueuedSends(Adapter, TRUE); if (fRescheduleThisDpcAgain) { TXScheduleTheSendComplete(Adapter); } DEBUGP(MP_TRACE, "[%p] <--- TXSendComplete.\n", Adapter); }
VOID TXQueueNetBufferForSend( _In_ PMP_ADAPTER Adapter, _In_ PNET_BUFFER NetBuffer) /*++ Routine Description: This routine inserts the NET_BUFFER into the SendWaitList, then calls TXTransmitQueuedSends to start sending data from the list. We use this indirect queue to send data because the miniport should try to send frames in the order in which the protocol gave them. If we just sent the NET_BUFFER immediately, then it would be out-of-order with any data on the SendWaitList. Runs at IRQL <= DISPATCH_LEVEL Arguments: Adapter Adapter that is transmitting this NB NetBuffer NB to be transfered Return Value: None. --*/ { NDIS_STATUS Status; UCHAR DestAddress[NIC_MACADDR_SIZE]; DEBUGP(MP_TRACE, "[%p] ---> TXQueueNetBufferForSend, NB= 0x%p\n", Adapter, NetBuffer); do { // // First, do a sanity check on the frame data. // Status = HWGetDestinationAddress(NetBuffer, DestAddress); if (Status != NDIS_STATUS_SUCCESS) { NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(NetBuffer)) = NDIS_STATUS_INVALID_DATA; break; } // // Stash away the frame type. We'll use that later, when updating // our send statistics (since we don't have NIC hardware to compute the // send statistics for us). // FRAME_TYPE_FROM_SEND_NB(NetBuffer) = NICGetFrameTypeFromDestination(DestAddress); // // Pin the original NBL with a reference, so it isn't completed until // we're done with its NB. // Status = TXNblReference(Adapter, NBL_FROM_SEND_NB(NetBuffer)); if(Status == NDIS_STATUS_SUCCESS) { // // Insert the NB into the queue. The caller will flush the queue when // it's done adding items to the queue. // NdisInterlockedInsertTailList( &Adapter->SendWaitList, SEND_WAIT_LIST_FROM_NB(NetBuffer), &Adapter->SendWaitListLock); } } while (FALSE); DEBUGP(MP_TRACE, "[%p] <--- TXQueueNetBufferForSend\n", Adapter); }
VOID RXReceiveIndicate( _In_ PMP_ADAPTER Adapter, _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc, BOOLEAN AtDpc) /*++ Routine Description: This function performs the receive indications for the specified RECEIVE_DPC structure. Runs at IRQL <= DISPATCH_LEVEL. Arguments: Adapter Pointer to our adapter AdapterDpc PMP_ADAPTER_RECEIVE_DPC structure for this receive AtDpc TRUE if the function was called from the context of the DPC, FALSE if called from work item (to avoid watchdog) Return Value: None. --*/ { ULONG NumNblsReceived = 0; PNET_BUFFER_LIST FirstNbl = NULL, LastNbl = NULL; USHORT CurrentQueue; DEBUGP(MP_TRACE, "[%p] ---> RXReceiveIndicate. Processor: %i, AtDpc: %i\n", Adapter, AdapterDpc->ProcessorNumber, AtDpc); // // Exit DPC if we've queued a work item to avoid DPC watchdog timer expiration // if(AtDpc && WorkItemQueuedForWatchdogAvoidance(AdapterDpc->WorkItem, &AdapterDpc->WorkItemQueued, RXReceiveIndicateWorkItem, AdapterDpc)) { DEBUGP(MP_TRACE, "[%p] <--- RXReceiveIndicate. Processor: %i\n", Adapter, AdapterDpc->ProcessorNumber); return; } for(CurrentQueue = 0; CurrentQueue <NIC_SUPPORTED_NUM_QUEUES; ++CurrentQueue) { // // Consume RCBs for queue if we're the assigned consumer // if(AdapterDpc->RecvBlock[CurrentQueue]) { PMP_ADAPTER_RECEIVE_BLOCK ReceiveBlock = &Adapter->ReceiveBlock[CurrentQueue]; FirstNbl = LastNbl = NULL; // // Collect pending NBLs, indicate up to MaxNblCountPerIndicate per receive block // for(NumNblsReceived=0; NumNblsReceived < AdapterDpc->MaxNblCountPerIndicate; ++NumNblsReceived) { PLIST_ENTRY Entry; PRCB Rcb = NULL; Entry = NdisInterlockedRemoveHeadList(&ReceiveBlock->ReceiveList, &ReceiveBlock->ReceiveListLock); if(Entry) { Rcb = CONTAINING_RECORD(Entry, RCB, RcbLink); } if(!Rcb) { break; } ASSERT(Rcb->Data); // // The recv NBL's data was filled out by the hardware. Now just update // its bookkeeping. // NET_BUFFER_LIST_STATUS(Rcb->Nbl) = NDIS_STATUS_SUCCESS; Rcb->Nbl->SourceHandle = Adapter->AdapterHandle; // // Add this NBL to the chain of NBLs to indicate up. // if (!FirstNbl) { LastNbl = FirstNbl = Rcb->Nbl; } else { NET_BUFFER_LIST_NEXT_NBL(LastNbl) = Rcb->Nbl; LastNbl = Rcb->Nbl; } } // // Indicate NBLs // if (FirstNbl) { DEBUGP(MP_TRACE, "[%p] Receive Block %i: %i frames indicated.\n", Adapter, CurrentQueue, NumNblsReceived); NET_BUFFER_LIST_NEXT_NBL(LastNbl) = NULL; // // Indicate up the NBLs. // // The NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL allows a perf optimization: // NDIS doesn't have to check and raise the current IRQL, since we // promise that the current IRQL is exactly DISPATCH_LEVEL already. // NdisMIndicateReceiveNetBufferLists( Adapter->AdapterHandle, FirstNbl, 0, // default port NumNblsReceived, (AtDpc?NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL:0) | NDIS_RECEIVE_FLAGS_PERFECT_FILTERED #if (NDIS_SUPPORT_NDIS620) | NDIS_RECEIVE_FLAGS_SINGLE_QUEUE | (CurrentQueue?NDIS_RECEIVE_FLAGS_SHARED_MEMORY_INFO_VALID:0) //non-default queues use shared memory #endif ); } if(!AtDpc) { // // Clear work item flag to allow DPCs to be queued // InterlockedExchange(&AdapterDpc->WorkItemQueued, FALSE); } if (!IsListEmpty(&ReceiveBlock->ReceiveList)) { // // More left to indicate for this receive block, queue this DPC again // DEBUGP(MP_TRACE, "[%p] Receive Block %i: Requeued DPC.\n", Adapter, CurrentQueue); KeInsertQueueDpc(&AdapterDpc->Dpc, AdapterDpc, NULL); } } } DEBUGP(MP_TRACE, "[%p] <--- RXReceiveIndicate. Processor: %i\n", Adapter, AdapterDpc->ProcessorNumber); }
/* SdrLLSendPacket transforms NDIS packet and enqueue it in MAC send queue. History: 3/Nov/2009: Created by senxiang */ VOID SdrLLSendPacket(PSDR_CONTEXT SDRContext, PNDIS_PACKET_OR_NBL pNBSPacket) { PMDL pEthBuffer = NULL; PMDL pWlanBuffer = NULL; PDLCB pDLCB = NULL; ULONG Dot11HeaderSize = 0; PUCHAR pDot11HeaderVa = NULL; PMAC pMac = (PMAC)SDRContext->Mac; PLL lnk = (PLL)SDRContext->LinkLayer; PSEND_QUEUE_MANAGER pSendQueueManager = GET_SEND_QUEUE_MANAGER(pMac); PNET_BUFFER pCurrentNB = NET_BUFFER_LIST_FIRST_NB(pNBSPacket); ULONG NetBufferCount = GetNetBufferCount(pNBSPacket); LIST_ENTRY DLCBList; BOOL fSufficientDLCBs = GetNFreeDLCB(&DLCBList, pSendQueueManager, NetBufferCount); DbgPrint("[LL_Send] %d net buffer in the NBL\n", NetBufferCount); if(pCurrentNB == NULL || !fSufficientDLCBs) { DbgPrint("[Error] Get NetBuffer failed, PACKET DROPPED\n"); NicDropPacket((PMP_ADAPTER)SDRContext->Nic, pNBSPacket); return; } NET_BUFFER_LIST_STATUS(pNBSPacket) = NDIS_STATUS_SUCCESS; //init its status to success while(pCurrentNB) { //Get MDL ASSERT(!IsListEmpty(&DLCBList)); pDLCB = CONTAINING_RECORD(RemoveHeadList(&DLCBList), DLCB, List); pDLCB->pNdisPktOrNBL = (PVOID)pNBSPacket; pDLCB->bLastNB = !(NET_BUFFER_NEXT_NB(pCurrentNB)); lnk->CurSendSeqNo.SequenceNumber++; pEthBuffer = NET_BUFFER_CURRENT_MDL(pCurrentNB); if(pEthBuffer == NULL) { pDLCB->PacketBase.pMdl = NULL; DbgPrint("[Error] Get MDL failed, PACKET DROPPED\n"); } else { EthToWlan(pEthBuffer, &pWlanBuffer, &Dot11HeaderSize, &pDot11HeaderVa, lnk->CurSendSeqNo.usValue, NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNB)); pDLCB->PacketType = PACKET_NEED_ACK; if(pDot11HeaderVa && (ETH_IS_BROADCAST(&((PDOT11RFC1042ENCAP)pDot11HeaderVa)->MacHeader.Address1) || ETH_IS_MULTICAST(&((PDOT11RFC1042ENCAP)pDot11HeaderVa)->MacHeader.Address1))) { pDLCB->PacketType = PACKET_NOT_NEED_ACK; } //Config DLCB pDLCB->Dot11HeaderSize = Dot11HeaderSize; pDLCB->pDot11HeaderVa = pDot11HeaderVa; pDLCB->PacketBase.pMdl = pWlanBuffer; pDLCB->PacketBase.PacketSize = NET_BUFFER_DATA_LENGTH(pCurrentNB) + sizeof(DOT11RFC1042ENCAP) - sizeof(ETHERNET_HEADER); { // we update the copied mdl length to packet length for baseband ULONG len = pDLCB->PacketBase.PacketSize; PMDL mdl = pDLCB->PacketBase.pMdl; while(mdl) { if (mdl->ByteCount > len) { mdl->ByteCount = len; break; } else if (mdl->ByteCount < len) { len-= mdl->ByteCount; mdl = mdl->Next; continue; } else break; } } pDLCB->PacketBase.Reserved1 = CalcMDLChainCRC32(pWlanBuffer); pDLCB->RetryCount = 0; pDLCB->bSendOK = FALSE; } SafeEnqueue(pSendQueueManager, SendSrcWaitList, pDLCB); InterlockedIncrement(&pSendQueueManager->nSrcPacket); //Notify send thread NIC_NOTIFY_SEND_THREAD(pMac); //Get next NetBuffer pCurrentNB = NET_BUFFER_NEXT_NB(pCurrentNB); } }
VOID NdisprotSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_BUFFER_LIST pNetBufferList, IN ULONG SendCompleteFlags ) /*++ Routine Description: NDIS entry point called to signify completion of a packet send. We pick up and complete the Write IRP corresponding to this packet. Arguments: ProtocolBindingContext - pointer to open context pNetBufferList - NetBufferList that completed send SendCompleteFlags - Specifies if the caller is at DISPATCH level Return Value: None --*/ { PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST CurrNetBufferList = NULL; PNET_BUFFER_LIST NextNetBufferList; NDIS_STATUS CompletionStatus; BOOLEAN DispatchLevel; pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext; NPROT_STRUCT_ASSERT(pOpenContext, oc); DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags); for (CurrNetBufferList = pNetBufferList; CurrNetBufferList != NULL; CurrNetBufferList = NextNetBufferList) { NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList); pIrp = NPROT_IRP_FROM_SEND_NBL(CurrNetBufferList); IoAcquireCancelSpinLock(&pIrp->CancelIrql); IoSetCancelRoutine(pIrp, NULL); pIrp->Tail.Overlay.DriverContext[0] = NULL; pIrp->Tail.Overlay.DriverContext[1] = NULL; IoReleaseCancelSpinLock(pIrp->CancelIrql); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry); NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList); // // We are done with the NDIS_PACKET: // NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel); // // Complete the Write IRP with the right status. // pIrpSp = IoGetCurrentIrpStackLocation(pIrp); if (CompletionStatus == NDIS_STATUS_SUCCESS) { pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length; pIrp->IoStatus.Status = STATUS_SUCCESS; } else { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d " "completed with status %x\n", CurrNetBufferList, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); pOpenContext->PendedSendCount--; if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING)) && (pOpenContext->PendedSendCount == 0)) { ASSERT(pOpenContext->ClosingEvent != NULL); NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent); pOpenContext->ClosingEvent = NULL; } NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP } }