⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sendrcv.c

📁 网络驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
    PURPOSE.

Module Name:

        SendRCV.C
        
Abstract:

    This module contains miniport functions for handling Send & Receive
    packets and other helper routines called by these miniport functions.

    In order to excercise the send and receive code path of this driver, 
    you should install more than one instance of the miniport. If there 
    is only one instance installed, the driver throws the send packet on
    the floor and completes the send successfully. If there are more 
    instances present, it indicates the incoming send packet to the other
    instances. For example, if there 3 instances: A, B, & C installed. 
    Packets coming in for A instance would be indicated to B & C; packets 
    coming into B would be indicated to C, & A; and packets coming to C 
    would be indicated to A & B. 
    
Revision History:

Notes:

--*/
#include "miniport.h"


VOID 
MPSendPackets(
    IN  NDIS_HANDLE             MiniportAdapterContext,
    IN  PPNDIS_PACKET           PacketArray,
    IN  UINT                    NumberOfPackets)
/*++

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 context
    PacketArray               Set of packets to send
    NumberOfPackets           Length of above array

Return Value:

    None
    
--*/
{
    PMP_ADAPTER       Adapter;
    NDIS_STATUS       Status;
    UINT              PacketCount;

    DEBUGP(MP_TRACE, ("---> MPSendPackets\n"));

    Adapter = (PMP_ADAPTER)MiniportAdapterContext;

    for(PacketCount=0;PacketCount < NumberOfPackets; PacketCount++)
    {
        //
        // Check for a zero pointer
        //
        ASSERT(PacketArray[PacketCount]);

        Status = NICSendPacket(Adapter, PacketArray[PacketCount]);

    }

    DEBUGP(MP_TRACE, ("<--- MPSendPackets\n"));

    return;
}

VOID 
MPReturnPacket(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PNDIS_PACKET Packet)
/*++

Routine Description:

    NDIS Miniport entry point called whenever protocols are done with
    a packet that we had indicated up and they had queued up for returning
    later.

Arguments:

    MiniportAdapterContext    - pointer to MP_ADAPTER structure
    Packet    - packet being returned.

Return Value:

    None.

--*/
{
    PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;

    DEBUGP(MP_TRACE, ("---> MPReturnPacket\n"));

    NICFreeRecvPacket(Adapter, Packet);
    
    DEBUGP(MP_TRACE, ("<--- MPReturnPacket\n"));
}



NDIS_STATUS 
NICSendPacket(
    PMP_ADAPTER Adapter,
    PNDIS_PACKET Packet)
/*++

Routine Description:

    This routine copies the packet content to a TCB, gets a receive packet,
    associates the TCB buffer to this recive packet and queues
    receive packet with the same data on one or more miniport instances
    controlled by this driver. For receive path to be active, you have
    to install more than one instance of this miniport.
        
Arguments:

    Adapter    - pointer to the MP_ADAPTER structure
    Packet    - packet to be transfered.


Return Value:

    NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING

--*/
{
    PMP_ADAPTER       DestAdapter;
    NDIS_STATUS       Status = NDIS_STATUS_SUCCESS;
    PTCB              pTCB = NULL;

    DEBUGP(MP_TRACE, ("--> NICSendPacket, Packet= %p\n", Packet));
    
    //
    // Go through the adapter list and queue packet for
    // indication on them if there are any. Otherwise
    // just drop the packet on the floor and tell NDIS that
    // you have completed send.
    //
    NdisAcquireSpinLock(&GlobalData.Lock);
    DestAdapter = (PMP_ADAPTER) &GlobalData.AdapterList;       

    while(MP_IS_READY(Adapter))
    {
        DestAdapter = (PMP_ADAPTER) DestAdapter->List.Flink;
        if((PLIST_ENTRY)DestAdapter == &GlobalData.AdapterList)
        {
            //
            // We have reached the end of the adapter list. So
            //
            break;
        }

        //
        // We wouldn't transmit the packet if:
        // a) The destination adapter is same as the Send Adapter.
        // b) The destination adapter is not ready to receive packets.
        // c) The packet itself is not worth transmitting.
        //
        if(DestAdapter == Adapter ||
            !MP_IS_READY(DestAdapter) || 
            !NICIsPacketTransmittable(DestAdapter, Packet))
        {
            continue;
        }
        
        DEBUGP(MP_LOUD, ("Packet is accepted...\n"));

        if(!pTCB)
        {
            //
            // Get a TCB from the SendFreelist.
            //
            NdisAcquireSpinLock(&Adapter->SendLock);            
            if(IsListEmpty(&Adapter->SendFreeList)){
                
                DEBUGP(MP_WARNING, ("TCB not available......!\n")); 

                Status = NDIS_STATUS_PENDING;    

                //
                // Not able to get TCB block for this send. So queue
                // it for later transmission and break out of the loop.
                //
                InsertTailList(
                    &Adapter->SendWaitList, 
                    (PLIST_ENTRY)&Packet->MiniportReserved[0] );
                
                NdisReleaseSpinLock(&Adapter->SendLock);            
                
                break;
            }
            else
            {
                pTCB = (PTCB) RemoveHeadList(&Adapter->SendFreeList);
                Adapter->nBusySend++;
                ASSERT(Adapter->nBusySend <= NIC_MAX_BUSY_SENDS);
                NdisReleaseSpinLock(&Adapter->SendLock);            
            
                //
                // Copy the packet content into the TCB data buffer, 
                // assuming the NIC is doing a common buffer DMA. For
                // scatter/gather DMA, this copy operation is not required.
                // For efficiency, I could have avoided the copy operation
                // in this driver and directly indicated the send buffers to 
                // other miniport instances since I'm holding the send packet
                // until all the indicated packets are returned. Oh, well!
                //
                if(!NICCopyPacket(Adapter, pTCB, Packet)){
                    DEBUGP(MP_ERROR, ("NICCopyPacket failed\n"));  
                    //
                    // Free the TCB and complete the send.
                    //
                    Status = NDIS_STATUS_FAILURE;
                    break;
                }
            }
        }

        Status = NDIS_STATUS_PENDING;    

        NICQueuePacketForRecvIndication(DestAdapter, pTCB);              

    } // while

    NdisReleaseSpinLock(&GlobalData.Lock);

    NDIS_SET_PACKET_STATUS(Packet, Status);

    if(NDIS_STATUS_SUCCESS == Status || 
        (pTCB && (NdisInterlockedDecrement(&pTCB->Ref) == 0)))
    {
        //
        // We will end up here if the Adapter is not ready, copypacket failed
        // above or the packet we indicated has already returned back to us.
        //
        DEBUGP(MP_LOUD, ("Calling NdisMSendComplete \n"));

        Status = NDIS_STATUS_SUCCESS;

        Adapter->GoodTransmits++;

        NdisMSendComplete(
            Adapter->AdapterHandle,
            Packet,
            Status);

        if(pTCB)
        {
            NICFreeSendTCB(Adapter, pTCB);
        }
    }

    DEBUGP(MP_TRACE, ("<-- NICSendPacket Status = 0x%08x\n", Status));

    return(Status);
}  



VOID
NICQueuePacketForRecvIndication(
    PMP_ADAPTER Adapter,
    PTCB pTCB)
/*++

Routine Description:

    This routine queues the send packet in to the destination
    adapters RecvWaitList and fires a timer DPC so that it 
    cab be indicated as soon as possible.

Arguments:

    Adapter    - pointer to the destination adapter structure
    pTCB      - pointer to TCB block
        

Return Value:

    VOID

--*/
{
    PNDIS_PACKET     SendPacket = pTCB->OrgSendPacket;
    PNDIS_PACKET     RecvPacket = NULL;
    PNDIS_BUFFER     CurrentBuffer = NULL;   
    UINT             NumPhysDesc, BufferCount, PacketLength, RecvPacketLength;             
    PLIST_ENTRY      pEntry;
    PRCB             pRCB;
    NDIS_STATUS      Status;
    

    DEBUGP(MP_TRACE, ("--> NICQueuePacketForRecvIndication\n"));

    //
    // Allocate memory for RCB. 
    //
    pRCB = NdisAllocateFromNPagedLookasideList(&Adapter->RecvLookaside);
    if(!pRCB)
    {
        DEBUGP(MP_ERROR, ("Failed to allocate memory for RCB\n"));
        return;
    }  
    
    //
    // Get a free recv packet descriptor from the list.
    //
    pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
                    &Adapter->RecvFreeList, 
                    &Adapter->RecvLock);
    if(!pEntry)
    {
        ++Adapter->RcvResourceErrors;
        NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pRCB);
    }
    else
    {
        ++Adapter->GoodReceives;
    
        RecvPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
        
        //
        // Prepare the recv packet
        //
        NdisReinitializePacket(RecvPacket);
        *((PTCB *)RecvPacket->MiniportReserved) = pTCB;

        //
        // Chain the TCB buffers to the packet
        //
        NdisChainBufferAtBack(RecvPacket, pTCB->Buffer);
                    
#if DBG
        NdisQueryPacket(
            RecvPacket,
            NULL,
            NULL,
            &CurrentBuffer,
            &RecvPacketLength);
    
        ASSERT(CurrentBuffer == pTCB->Buffer);
        
        NdisQueryPacket(
            SendPacket,
            NULL,
            NULL,
            NULL,
            &PacketLength);
    
        if((RecvPacketLength != 60) && (RecvPacketLength != PacketLength))
        {
            DEBUGP(MP_ERROR, ("RecvPacketLength = %d, PacketLength = %d\n",
                RecvPacketLength, PacketLength));
            DEBUGP(MP_ERROR, ("RecvPacket = %p, Packet = %p\n",
                RecvPacket, SendPacket));
            ASSERT(FALSE);
        }
#endif    
                  
        NDIS_SET_PACKET_STATUS(RecvPacket, NDIS_STATUS_SUCCESS);
    
        DEBUGP(MP_LOUD, ("RecvPkt= %p\n", RecvPacket));

        //
        // Initialize RCB 
        //
        NdisInitializeListHead(&pRCB->List);
        pRCB->Packet = RecvPacket;
        
        //
        // Increment the Ref count on the TCB to denote that it's being
        // used. This reference will be removed when the indicated
        // Recv packet finally returns from the protocol.
        //
        NdisInterlockedIncrement(&pTCB->Ref);     

        //
        // Insert the packet in the recv wait queue to be picked up by
        // the receive indication DPC.
        // 
        NdisAcquireSpinLock(&Adapter->RecvLock);
        InsertTailList(&Adapter->RecvWaitList, 
                            &pRCB->List);
        Adapter->nBusyRecv++;     
        ASSERT(Adapter->nBusyRecv <= NIC_MAX_BUSY_RECVS);
        NdisReleaseSpinLock(&Adapter->RecvLock);

        //
        // Fire a timer DPC. By specifing zero timeout, the DPC will
        // be serviced whenever the next system timer interrupt arrives.
        //
        NdisMSetTimer(&Adapter->RecvTimer, 0);
    
    }

    DEBUGP(MP_TRACE, ("<-- NICQueuePacketForRecvIndication\n"));
}

VOID
NICIndicateReceiveTimerDpc(
    IN PVOID             SystemSpecific1,
    IN PVOID             FunctionContext,
    IN PVOID             SystemSpecific2,
    IN PVOID             SystemSpecific3)
/*++

Routine Description:

    Timer callback function for Receive Indication. Please note that receive
    timer DPC is not required when you are talking to a real device. In real
    miniports, this DPC is usually provided by NDIS as MPHandleInterrupt
    callback whenever the device interrupts for receive indication.
        
Arguments:

FunctionContext - Pointer to our adapter

Return Value:

    VOID

--*/
{
    PMP_ADAPTER Adapter = (PMP_ADAPTER)FunctionContext;
    PRCB pRCB = NULL;
    PLIST_ENTRY pEntry = NULL;
    
    DEBUGP(MP_TRACE, ("--->NICIndicateReceiveTimerDpc = %p\n", Adapter));

    //
    // Increment the ref count on the adapter to prevent the driver from
    // unloding while the DPC is running. The Halt handler waits for the
    // ref count to drop to zero before returning. 
    //
    MP_INC_REF(Adapter); 
    
    //
    // Remove the packet from waitlist and indicate it to the protocols
    // above us.
    //
    while (pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
                    &Adapter->RecvWaitList, 
                    &Adapter->RecvLock)) {
    
        pRCB = CONTAINING_RECORD(pEntry, RCB, List);

        ASSERT(pRCB);
        ASSERT(pRCB->Packet);
        
        DEBUGP(MP_LOUD, ("Indicating packet = %p\n", pRCB->Packet));
        
        NdisMIndicateReceivePacket(
            Adapter->AdapterHandle,
            &pRCB->Packet,
            1);
        
        //
        // We are done with RCB memory. So free it.
        //
        NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pRCB);
        
    }
    
    MP_DEC_REF(Adapter);
    DEBUGP(MP_TRACE, ("<---NICIndicateReceiveTimerDpc\n"));    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -