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);

}
Ejemplo n.º 2
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
            );
    }

}
Ejemplo n.º 3
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);
		}
	}
}
Ejemplo n.º 4
0
/*
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);
}
Ejemplo n.º 5
0
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 ();
    }
}
Ejemplo n.º 6
0
// 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;
}
Ejemplo n.º 7
0
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);
}