VOID ParaNdis_IndicateReceivedBatch( PARANDIS_ADAPTER *pContext, tPacketIndicationType *pBatch, ULONG nofPackets) { ULONG i; PNET_BUFFER_LIST pPrev = pBatch[0]; NET_BUFFER_LIST_NEXT_NBL(pPrev) = NULL; for (i = 1; i < nofPackets; ++i) { PNET_BUFFER_LIST pNBL = pBatch[i]; NET_BUFFER_LIST_NEXT_NBL(pPrev) = pNBL; NET_BUFFER_LIST_NEXT_NBL(pNBL) = NULL; pPrev = pNBL; } NdisMIndicateReceiveNetBufferLists( pContext->MiniportHandle, pBatch[0], 0, nofPackets, 0); }
VOID BasePortIndicateReceivePackets( __in PMP_PORT Port, __in PMP_RX_MSDU PacketList, __in ULONG ReceiveFlags ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PMP_RX_MSDU currentPacket = PacketList, nextPacket; PMP_RX_MSDU packetListToIndicate = NULL, prevPacketToIndicate = NULL; PMP_RX_MSDU packetListToReturn = NULL, prevPacketToReturn = NULL; PNET_BUFFER_LIST nblChainToIndicate; ULONG indicateCount = 0; ULONG returnCount = 0; // // Currently the lower layer only indicates single MSDUs. We cannot handle // receiving more than one MSDU since we break the chain that the HW provides // and that is not acceptable in the RESOURCES case // MPASSERT(MP_RX_MSDU_NEXT_MSDU(currentPacket) == NULL); // Process each of the packets internally while (currentPacket != NULL) { nextPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket); MP_RX_MSDU_NEXT_MSDU(currentPacket) = NULL; do { // // Pass the packet to the port to determine if this // packet should be indicated up to the OS or not // ndisStatus = Port11NotifyReceive(Port, currentPacket, ReceiveFlags); if (ndisStatus == NDIS_STATUS_SUCCESS) { // We only pass 1 packet at a time to the port, // lets look at whether we should indicate this packet up to // the OS or not ndisStatus = MP_RX_MSDU_STATUS(currentPacket); } if (ndisStatus != NDIS_STATUS_SUCCESS) { // This packet should not be indicated up break; } // Perform filtering of the packet to determine if this need to go up to the OS if (BasePortFilterFragment(Port, currentPacket) == FALSE) { // Drop these packets ndisStatus = NDIS_STATUS_NOT_ACCEPTED; // Since we have already given this packet to the port, let it undo // anything it may have done before Port11NotifyReturn(Port, currentPacket, NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0 ); break; } } while (FALSE); if (ndisStatus == NDIS_STATUS_SUCCESS) { // This packet gets indicated to the OS if (packetListToIndicate == NULL) { packetListToIndicate = currentPacket; } else { MP_RX_MSDU_NEXT_MSDU(prevPacketToIndicate) = currentPacket; } indicateCount++; prevPacketToIndicate = currentPacket; // // From this point on the packets must be completed // } else { // This (failed) packet gets returned back to the HW if (packetListToReturn == NULL) { packetListToReturn = currentPacket; } else { MP_RX_MSDU_NEXT_MSDU(prevPacketToReturn) = currentPacket; } returnCount++; prevPacketToReturn = currentPacket; } // Next packet currentPacket = nextPacket; } // Convert the packets we want to indicate into if (packetListToIndicate != NULL) { ndisStatus = BasePortTranslateRxPacketsToRxNBLs(Port, packetListToIndicate, &nblChainToIndicate ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_SEND, DBG_SERIOUS, ("Failed to allocate NET_BUFFER_LIST chain for MP_RX_MSDU chain\n")); // // Notify port that these packets have been returned // Port11NotifyReturn(Port, packetListToIndicate, NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0 ); // // Prepend these "failed" MSDUs to the list that we wont indicate to the OS. These // would get freed below. The order doesnt matter here // currentPacket = packetListToIndicate; while (currentPacket != NULL) { nextPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket); MP_RX_MSDU_NEXT_MSDU(currentPacket) = packetListToReturn; packetListToReturn = currentPacket; currentPacket = nextPacket; returnCount++; } } else { if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags)) { // // Increment the counter for the number of packets we have submitted // to the OS. This would block the port from pausing, etc // PORT_ADD_PNP_REFCOUNT(Port, indicateCount); } // Indicate these to the OS NdisMIndicateReceiveNetBufferLists( Port->MiniportAdapterHandle, nblChainToIndicate, Port->PortNumber, indicateCount, ReceiveFlags ); if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags)) { // We wont get a return for these. Free the NBLs BasePortFreeTranslatedRxNBLs(Port, nblChainToIndicate); // Notify the ports about the return Port11NotifyReturn(Port, packetListToIndicate, NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0 ); } } } // Return all the non-used packets back to the HW (if we are permitted to call // return) if ((packetListToReturn != NULL) && (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))) { VNic11ReturnPackets(Port->VNic, packetListToReturn, NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0 ); } }
// Process the received packet void NeoWrite(void *buf) { UINT num, i, size; UCHAR *packet_buf; NET_BUFFER_LIST *nbl_chain = NULL; NET_BUFFER_LIST *nbl_tail = NULL; UINT num_nbl_chain = 0; // Validate arguments if (buf == NULL) { return; } // Number of packets num = NEO_NUM_PACKET(buf); if (num > NEO_MAX_PACKET_EXCHANGE) { // Number of packets is too many return; } if (num == 0) { // No packet return; } if (ctx->Halting != FALSE) { // Stopping return; } if (ctx->Paused) { // Paused return; } if (ctx->Opened == FALSE) { // Not connected return; } for (i = 0;i < num;i++) { PACKET_BUFFER *p = ctx->PacketBuffer[i]; void *dst; NET_BUFFER_LIST *nbl = ctx->PacketBuffer[i]->NetBufferList; NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); nbl->SourceHandle = ctx->NdisMiniport; NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL; size = NEO_SIZE_OF_PACKET(buf, i); if (size > NEO_MAX_PACKET_SIZE) { size = NEO_MAX_PACKET_SIZE; } if (size < NEO_PACKET_HEADER_SIZE) { size = NEO_PACKET_HEADER_SIZE; } packet_buf = (UCHAR *)(NEO_ADDR_OF_PACKET(buf, i)); if (OK(NdisRetreatNetBufferDataStart(nb, size, 0, NULL))) { // Buffer copy dst = NdisGetDataBuffer(nb, size, NULL, 1, 0); if (dst != NULL) { NeoCopy(dst, packet_buf, size); if (nbl_chain == NULL) { nbl_chain = nbl; } if (nbl_tail != NULL) { NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl; } nbl_tail = nbl; num_nbl_chain++; } } nbl->Status = NDIS_STATUS_RESOURCES; ctx->Status.Int64BytesRecvTotal += (UINT64)size; if (packet_buf[0] & 0x40) { ctx->Status.Int64NumRecvBroadcast++; ctx->Status.Int64BytesRecvBroadcast += (UINT64)size; } else { ctx->Status.Int64NumRecvUnicast++; ctx->Status.Int64BytesRecvUnicast += (UINT64)size; } } if (nbl_chain == NULL) { return; } // Notify that it has received ctx->Status.NumPacketRecv += num_nbl_chain; NdisMIndicateReceiveNetBufferLists(ctx->NdisMiniport, nbl_chain, 0, num_nbl_chain, NDIS_RECEIVE_FLAGS_RESOURCES); if (true) { // Restore the packet buffer NET_BUFFER_LIST *nbl = nbl_chain; while (nbl != NULL) { NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl); if (nb != NULL) { UINT size = NET_BUFFER_DATA_LENGTH(nb); NdisAdvanceNetBufferDataStart(nb, size, false, NULL); } nbl = NET_BUFFER_LIST_NEXT_NBL(nbl); } } }
/* NicIndicateRecvPackets indicate received packet (MAC frame) to NDIS (then protocol stack) Parameters: pAdapter : pointer to adapter object created by miniport driver. ppNdisPacket : pointer to an NDIS packet to be indicated up. Return: Note: History: Created by yichen, 1/Apr/2009 IRQL: PASSIVE_LEVEL */ VOID NicIndicateRecvPackets(IN PMP_ADAPTER pAdapter, IN PPNDIS_PACKETS_OR_NBL ppNBSPackets) { NdisMIndicateReceiveNetBufferLists(pAdapter->AdapterHandle, ppNBSPackets, pAdapter->PortNumber, 1, 0); InterlockedIncrement64(&pAdapter->ullGoodReceives); }
VOID IndicateReceivePacket( __in PTAP_ADAPTER_CONTEXT Adapter, __in PUCHAR packetData, __in const unsigned int packetLength ) { PUCHAR injectBuffer; // // Handle miniport Pause // --------------------- // NDIS 6 miniports implement a temporary "Pause" state normally followed // by the Restart. While in the Pause state it is forbidden for the miniport // to indicate receive NBLs. // // That is: The device interface may be "up", but the NDIS miniport send/receive // interface may be temporarily "down". // // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path // the code below will simply ignore inject packets passed to the driver while // the miniport is in the Paused state. // // The correct implementation is to go ahead and build the NBLs corresponding // to the inject packet - but queue them. When Restart is entered the // queued NBLs would be dequeued and indicated to the host. // if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS) { DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n", MINIPORT_INSTANCE_ID (Adapter))); return; } // Allocate flat buffer for packet data. injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority( Adapter->MiniportAdapterHandle, packetLength, TAP_RX_INJECT_BUFFER_TAG, NormalPoolPriority ); if( injectBuffer) { PMDL mdl; // Copy packet data to flat buffer. NdisMoveMemory (injectBuffer, packetData, packetLength); // Allocate MDL for flat buffer. mdl = NdisAllocateMdl( Adapter->MiniportAdapterHandle, injectBuffer, packetLength ); if( mdl ) { PNET_BUFFER_LIST netBufferList; mdl->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( Adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill mdl, // MDL chain 0, packetLength ); if(netBufferList != NULL) { ULONG receiveFlags = 0; LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL if(KeGetCurrentIrql() == DISPATCH_LEVEL) { receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; } // Set flag indicating that this is an injected packet TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED); netBufferList->MiniportReserved[0] = NULL; netBufferList->MiniportReserved[1] = NULL; // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); netBufferList->SourceHandle = Adapter->MiniportAdapterHandle; // // Indicate the packet // ------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the complete packet including Ethernet header and payload. // NdisMIndicateReceiveNetBufferLists( Adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists receiveFlags ); return; } else { DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); NdisFreeMdl(mdl); NdisFreeMemory(injectBuffer,0,0); } } else { DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); NdisFreeMemory(injectBuffer,0,0); } } else { DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); } }
// IRP_MJ_WRITE callback. NTSTATUS TapDeviceWrite( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success PIO_STACK_LOCATION irpSp;// Pointer to current stack location PTAP_ADAPTER_CONTEXT adapter = NULL; ULONG dataLength; PAGED_CODE(); irpSp = IoGetCurrentIrpStackLocation( Irp ); // // Fetch adapter context for this device. // -------------------------------------- // Adapter pointer was stashed in FsContext when handle was opened. // adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; ASSERT(adapter); // // Sanity checks on state variables // if (!tapAdapterReadAndWriteReady(adapter)) { //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", // MINIPORT_INSTANCE_ID (adapter))); //NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } // Save IRP-accessible copy of buffer length Irp->IoStatus.Information = irpSp->Parameters.Write.Length; if (Irp->MdlAddress == NULL) { DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } // // Try to get a virtual address for the MDL. // NdisQueryMdl( Irp->MdlAddress, &Irp->AssociatedIrp.SystemBuffer, &dataLength, NormalPagePriority ); if (Irp->AssociatedIrp.SystemBuffer == NULL) { DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } ASSERT(dataLength == irpSp->Parameters.Write.Length); Irp->IoStatus.Information = irpSp->Parameters.Write.Length; // // Handle miniport Pause // --------------------- // NDIS 6 miniports implement a temporary "Pause" state normally followed // by the Restart. While in the Pause state it is forbidden for the miniport // to indicate receive NBLs. // // That is: The device interface may be "up", but the NDIS miniport send/receive // interface may be temporarily "down". // // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path // the code below will perform a "lying send" for write IRPs passed to the // driver while the miniport is in the Paused state. // // The correct implementation is to go ahead and build the NBLs corresponding // to the user-mode write - but queue them. When Restart is entered the // queued NBLs would be dequeued and indicated to the host. // if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) { if (!adapter->m_tun && ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) { PNET_BUFFER_LIST netBufferList; DUMP_PACKET ("IRP_MJ_WRITE ETH", (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length); //===================================================== // If IPv4 packet, check whether or not packet // was truncated. //===================================================== #if PACKET_TRUNCATION_CHECK IPv4PacketSizeVerify ( (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length, FALSE, "RX", &adapter->m_RxTrunc ); #endif (Irp->MdlAddress)->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill Irp->MdlAddress, // MDL chain 0, dataLength ); if(netBufferList != NULL) { LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL // Stash IRP pointer in NBL MiniportReserved[0] field. netBufferList->MiniportReserved[0] = Irp; netBufferList->MiniportReserved[1] = NULL; // BUGBUG!!! Setup for IRP cancel!!! TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); // // Indicate the packet // ------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the complete packet including Ethernet header and payload. // NdisMIndicateReceiveNetBufferLists( adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists 0 // ReceiveFlags ); ntStatus = STATUS_PENDING; } else { DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) { PETH_HEADER p_UserToTap = &adapter->m_UserToTap; PMDL mdl; // Head of MDL chain. // For IPv6, need to use Ethernet header with IPv6 proto if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 ) { p_UserToTap = &adapter->m_UserToTap_IPv6; } DUMP_PACKET2 ("IRP_MJ_WRITE P2P", p_UserToTap, (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length); //===================================================== // If IPv4 packet, check whether or not packet // was truncated. //===================================================== #if PACKET_TRUNCATION_CHECK IPv4PacketSizeVerify ( (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length, TRUE, "RX", &adapter->m_RxTrunc ); #endif // // Allocate MDL for Ethernet header // -------------------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the only the Ethernet payload. Prepend the user-mode provided // payload with the Ethernet header pointed to by p_UserToTap. // mdl = NdisAllocateMdl( adapter->MiniportAdapterHandle, p_UserToTap, sizeof(ETH_HEADER) ); if(mdl != NULL) { PNET_BUFFER_LIST netBufferList; // Chain user's Ethernet payload behind Ethernet header. mdl->Next = Irp->MdlAddress; (Irp->MdlAddress)->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill mdl, // MDL chain 0, sizeof(ETH_HEADER) + dataLength ); if(netBufferList != NULL) { LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL // This IRP is pended. IoMarkIrpPending(Irp); // This IRP cannot be cancelled while in-flight. IoSetCancelRoutine(Irp,NULL); // Stash IRP pointer in NBL MiniportReserved[0] field. netBufferList->MiniportReserved[0] = Irp; netBufferList->MiniportReserved[1] = NULL; // Set flag indicating that this is P2P packet TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P); // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); // // Indicate the packet // NdisMIndicateReceiveNetBufferLists( adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists 0 // ReceiveFlags ); ntStatus = STATUS_PENDING; } else { mdl->Next = NULL; NdisFreeMdl(mdl); DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else { DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else { DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", MINIPORT_INSTANCE_ID (adapter), irpSp->Parameters.Write.Length)); NOTE_ERROR (); Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; } } else { DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n", MINIPORT_INSTANCE_ID (adapter))); ntStatus = STATUS_SUCCESS; } if (ntStatus != STATUS_PENDING) { Irp->IoStatus.Status = ntStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return ntStatus; }
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); }