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 BasePortTransmitQueuedPackets( __in PMP_PORT Port, __in ULONG SendFlags ) { PMP_TX_MSDU currentPacket, prevPacketToForward = NULL, packetListToForward = NULL; ULONG count = 0, numPktToFwd = 0; NDIS_STATUS ndisStatus; PMP_TX_MSDU packetListToFail = NULL; // PORT_LOCK must be held // If I am pausing, this flag is set. We would not // be processing any pending packets. These packets get flushed on a pause // then not process these pending packets if (MP_TEST_PORT_STATUS(Port, MP_PORT_CANNOT_SEND_MASK)) { // // We dont do anything // MpTrace(COMP_SEND, DBG_NORMAL, ("Dropping sends as port should not be sending\n")); return; } while ((!MpPacketQueueIsEmpty(&Port->PendingTxQueue) && (count < MAX_SEND_MSDU_TO_PROCESS))) { // // Dequeue the first packet from the list // currentPacket = MP_MSDU_FROM_QUEUE_ENTRY(MpDequeuePacket(&Port->PendingTxQueue)); count++; // // Let the port pre-process the packets. We only let one // packet to get processed at a time // MP_TX_MSDU_NEXT_MSDU(currentPacket) = NULL; MP_TX_MSDU_STATUS(currentPacket) = NDIS_STATUS_SUCCESS; ndisStatus = Port11NotifySend(Port, currentPacket, SendFlags); if (ndisStatus == NDIS_STATUS_SUCCESS) { // // Look at the per-packet status values // ndisStatus = MP_TX_MSDU_STATUS(currentPacket); if (ndisStatus == NDIS_STATUS_SUCCESS) { // // Port is fine with processing these packets. Let us check if we can // continue sending this down. We only check with the VNIC // if (VNic11CanTransmit(PORT_GET_VNIC(Port)) == FALSE) { // // Some reason we cannot submit this packet to the // HW yet. Queue it in the pending Tx queue // ndisStatus = NDIS_STATUS_PENDING; // // In this case we indicate the packet to the Port again // the next time we attempt to send. Ensure that the port // can handle that // } } } else { // // Port returned PENDING or FAILURE for the packet list. We wont // be sending any of these packets // } // // All the above processing would give us one of the following status codes // // NDIS_STATUS_SUCCESS - The packets can be processed furthers. In this case // we forward the packet to the lower layer // NDIS_STATUS_PENDING - This packet should not be sent now, but can be sent later // In this case we requeue the packet and stop processing // further packets // NDIS_STATUS_FAILURE or anything other failure status // - The packet is not sent and we continue processing // other packets if (ndisStatus == NDIS_STATUS_SUCCESS) { numPktToFwd++; // Add this to the end of the chain we are forwarding to the HW if (packetListToForward == NULL) { packetListToForward = currentPacket; } else { MP_TX_MSDU_NEXT_MSDU(prevPacketToForward) = currentPacket; } prevPacketToForward = currentPacket; // // Increment the counter for the number of packets we have submitted // to the hardware. This would block the port from pausing, etc // PORT_INCREMENT_PNP_REFCOUNT(Port); } else if (ndisStatus == NDIS_STATUS_PENDING) { // // Put the packet back at the head of the packet queue. To avoid out of // order delivery we dont go forward and give any more packets to the // lower layer // MpQueuePacketPriority(&Port->PendingTxQueue, QUEUE_ENTRY_FROM_MP_MSDU(currentPacket)); break; } else { // // Put this packet in the list of packets to be failed // MpTrace(COMP_SEND, DBG_NORMAL, ("Port or VNic failed sends with status 0x%08x\n", ndisStatus)); MP_TX_MSDU_STATUS(currentPacket) = ndisStatus; MP_TX_MSDU_NEXT_MSDU(currentPacket) = packetListToFail; packetListToFail = currentPacket; } } if ((packetListToForward != NULL) || (packetListToFail != NULL)) { // Forward this list to the VNIC MP_RELEASE_PORT_LOCK(Port, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags)); if (packetListToForward != NULL) { VNic11SendPackets(PORT_GET_VNIC(Port), packetListToForward, numPktToFwd, SendFlags); } // // Complete the failed packets // if (packetListToFail != NULL) { BasePortCompleteFailedPackets(Port, packetListToFail, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0 ); } MP_ACQUIRE_PORT_LOCK(Port, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags)); } }
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 SxLibSendNetBufferListsIngress( _In_ PSX_SWITCH_OBJECT Switch, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ ULONG SendFlags, _In_ ULONG NumInjectedNetBufferLists ) { BOOLEAN dispatch; BOOLEAN sameSource; ULONG sendCompleteFlags; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail; PNET_BUFFER_LIST curNbl, nextNbl; ULONG numNbls = 0; PNET_BUFFER_LIST dropNbl = NULL; PNET_BUFFER_LIST *curDropNbl = &dropNbl; NDIS_SWITCH_PORT_ID curSourcePort; NDIS_STRING filterReason; dispatch = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); sameSource = NDIS_TEST_SEND_FLAG(SendFlags, NDIS_SEND_FLAGS_SWITCH_SINGLE_SOURCE); InterlockedAdd(&Switch->PendingInjectedNblCount, NumInjectedNetBufferLists); KeMemoryBarrier(); if (Switch->DataFlowState != SxSwitchRunning) { RtlInitUnicodeString(&filterReason, L"Extension Paused"); sendCompleteFlags = (dispatch) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0; sendCompleteFlags |= (sameSource) ? NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE : 0; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists); if (sameSource) { for (curNbl = NetBufferLists; curNbl != NULL; curNbl = curNbl->Next) { ++numNbls; } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, fwdDetail->SourcePortId, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, NetBufferLists, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, NetBufferLists, sendCompleteFlags); } else { curSourcePort = fwdDetail->SourcePortId; for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl) { nextNbl = curNbl->Next; curNbl->Next = NULL; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl); if(curSourcePort == fwdDetail->SourcePortId) { *curDropNbl = curNbl; curDropNbl = &(curNbl->Next); ++numNbls; } else { Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, dropNbl, sendCompleteFlags); numNbls = 1; dropNbl = curNbl; curDropNbl = &(curNbl->Next); curSourcePort = fwdDetail->SourcePortId; } } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, dropNbl, sendCompleteFlags); } goto Cleanup; } NdisFSendNetBufferLists(Switch->NdisFilterHandle, NetBufferLists, NDIS_DEFAULT_PORT_NUMBER, SendFlags); Cleanup: return; }
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 } }