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

📄 send.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:

        Send.C
        
Abstract:

    This module contains miniport functions for handling Send
    packets and other helper routines called by the miniport function.

Author:  Eliyas Yakub (Jan 11, 2003)

    
Revision History:

Notes:

--*/
#include "ndiswdm.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;
    UINT              PacketCount;
    PNDIS_PACKET      Packet = NULL;
    NDIS_STATUS       Status = NDIS_STATUS_FAILURE;
    PTCB              pTCB = NULL;
    NTSTATUS          ntStatus;
    
    DEBUGP(MP_TRACE, ("---> MPSendPackets\n"));

    Adapter = (PMP_ADAPTER)MiniportAdapterContext;

    for(PacketCount=0; PacketCount < NumberOfPackets; PacketCount++)
    {
        //
        // Check for a zero pointer
        //
        
        Packet = PacketArray[PacketCount];
        
        if(!Packet){
            ASSERTMSG("Packet pointer is NULL\n", FALSE);
            continue;
        }
        
        DEBUGP(MP_LOUD, ("Adapter %p, Packet %p\n", Adapter, Packet));
        
        Adapter->nPacketsArrived++;
        
        if(MP_IS_READY(Adapter) && MP_TEST_FLAG(Adapter, fMP_POST_WRITES))
        {
            //
            // Get a free TCB block 
            //
            pTCB = (PTCB) NdisInterlockedRemoveHeadList(
                         &Adapter->SendFreeList, 
                         &Adapter->SendLock);        
            if(pTCB == NULL)
            {            
                DEBUGP(MP_LOUD, ("Can't allocate a TCB......!\n")); 

                Status = NDIS_STATUS_PENDING;    

                //
                // Not able to get TCB block for this send. So queue
                // it for later transmission and return NDIS_STATUS_PENDING .
                //
                NdisInterlockedInsertTailList(
                    &Adapter->SendWaitList, 
                    (PLIST_ENTRY)&Packet->MiniportReserved[0], 
                    &Adapter->SendLock);
            }
            else
            {    
                NdisInterlockedIncrement(&Adapter->nBusySend);
                ASSERT(Adapter->nBusySend <= NIC_MAX_BUSY_SENDS);

                //
                // Copy the content of the packet to a TCB block
                // buffer. We need to do this because the target driver
                // is not capable of handling chained buffers.
                //
                if(NICCopyPacket(Adapter, pTCB, Packet)) 
                {
                    Adapter->nWritesPosted++;
                    //
                    // Post a asynchronouse write request.
                    //
                    ntStatus = NICPostWriteRequest(Adapter, pTCB);
                    
                    if ( !NT_SUCCESS ( ntStatus ) ) {
                        DEBUGP (MP_ERROR, ( "NICPostWriteRequest failed %x\n", ntStatus ));
                    } 
                    NT_STATUS_TO_NDIS_STATUS(ntStatus, &Status);
                                        
                }else {
                    DEBUGP(MP_ERROR, ("NICCopyPacket returned error\n"));
                    Status = NDIS_STATUS_FAILURE;                
                }
            }
        }

        if(!NT_SUCCESS(Status)) // yes, NT_SUCCESS macro can be used on NDIS_STATUS
        {

            DEBUGP(MP_LOUD, ("Calling NdisMSendComplete %x \n", Status));
            
            NDIS_SET_PACKET_STATUS(Packet, Status);

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

            if(pTCB && (NdisInterlockedDecrement(&pTCB->Ref) == 0))
            {
                NICFreeSendTCB(Adapter, pTCB);
            }
        }


    }

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

    return;
}



NTSTATUS
NICPostWriteRequest(
    PMP_ADAPTER Adapter,
    PTCB    pTCB
    )
/*++

Routine Description:

    This routine posts a write IRP to the target device to send
    the network packet out to the device.
        
Arguments:

    Adapter    - pointer to the MP_ADAPTER structure
    PTCB    -  Pointer to the TCB block that contains the IRP and data.


Return Value:

    NT status code

--*/
{
    PIRP            irp = pTCB->Irp;
    PIO_STACK_LOCATION  nextStack;
    PDEVICE_OBJECT   TargetDeviceObject = Adapter->TargetDeviceObject;

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

    // 
    // Obtain a pointer to the stack location of the first driver that will be
    // invoked.  This is where the function codes and the parameters are set.
    // 
    nextStack = IoGetNextIrpStackLocation( irp );
    nextStack->MajorFunction = IRP_MJ_WRITE;
    nextStack->Parameters.Write.Length = pTCB->ulSize;
    nextStack->FileObject = Adapter->FileObject;
    
    irp->MdlAddress = (PMDL) pTCB->Mdl;

    pTCB->IrpLock = IRPLOCK_CANCELABLE;
        
    IoSetCompletionRoutine(irp,
                   NICWriteRequestCompletion,
                   pTCB,
                   TRUE,
                   TRUE,
                   TRUE);

    //
    // We are making an asynchronous request, so we don't really care
    // about the return status of IoCallDriver.
    //
    (void) IoCallDriver(TargetDeviceObject, irp);

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

    return STATUS_SUCCESS;
}

NTSTATUS
NICWriteRequestCompletion(
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
/*++

Routine Description:

    Completion routine for the write request. This routine
    indicates to NDIS that send operation is complete and
    free the TCB if nobody has already done so. This routine
    also handles the case where another thread has canceled the 
    write request.
        
Arguments:

    DeviceObject    -  not used. Should be NULL
    Irp    -   Pointer to our IRP
    Context - pointer to our adapter context structure

Return Value:

    STATUS_MORE_PROCESSING_REQUIRED - because this is an asynchronouse IRP
    and we want to reuse it.
    
--*/
{
    PTCB    pTCB = (PTCB)Context;
    PMP_ADAPTER Adapter = pTCB->Adapter;
    PLIST_ENTRY       pEntry = NULL;
    PNDIS_PACKET      Packet = NULL;

    DEBUGP(MP_TRACE, ("--> NICWriteRequestCompletion\n"));
    
    if(NT_SUCCESS(Irp->IoStatus.Status)) {  
        
        DEBUGP (MP_VERY_LOUD, ("Wrote %d bytes\n", Irp->IoStatus.Information)); 
        Adapter->GoodTransmits++; 
        Adapter->nBytesWritten += (ULONG)Irp->IoStatus.Information;
        
    } else {
    
        DEBUGP (MP_ERROR, ("Write request failed %x\n", Irp->IoStatus.Status));        
        Adapter->nWritesCompletedWithError++;   
        //
        // Clear the flag to prevent any more writes from being
        // posted to the target device.
        //
        //MP_CLEAR_FLAG(Adapter, fMP_POST_WRITES);
       
    }

    //
    // Check to see if another thread has canceled this IRP.
    //
    if (InterlockedExchange((PVOID)&pTCB->IrpLock, IRPLOCK_COMPLETED) 
                    == IRPLOCK_CANCEL_STARTED) {
        // 
        // NICFreeBusySendPackets has got the control of the IRP. It will
        // now take the responsibility of freeing the TCB. 
        // Therefore...
        
        return STATUS_MORE_PROCESSING_REQUIRED;
    }
    
    if(NdisInterlockedDecrement(&pTCB->Ref) == 0)
    {
        DEBUGP(MP_VERY_LOUD, ("Calling NdisMSendComplete \n"));

        Packet = pTCB->OrgSendPacket;

        //
        // For performance, let us free the TCB block before completing send.
        //
        NICFreeSendTCB(Adapter, pTCB);        

        NdisMSendComplete(
            Adapter->AdapterHandle,
            Packet,
            NDIS_STATUS_SUCCESS);
    
        //
        // Before we exit, since we have the control, let use see if there any 
        // more packets waiting in the queue to be sent.
        //
        
        pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
                            &Adapter->SendWaitList, 
                            &Adapter->SendLock);
        if(pEntry)
        {
            Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
            //
            // TODO: This can cause recursion if the target driver completes 
            // write requests synchronously. Use workitem to avoid recursion.
            //
            MPSendPackets(Adapter, &Packet, 1);             
        }
        
    }

    
    return STATUS_MORE_PROCESSING_REQUIRED;
}

VOID
NICFreeBusySendPackets(
    PMP_ADAPTER Adapter
    )
/*++

Routine Description:

    This routine is called by the Halt handler to cancel any
    outstanding write requests.

    Note: Since we are holding the original sendpacket while
    writing to the device, and since NDIS calls halt
    handler only all the outstanding sends are completed, this
    routine will never find any busy sendpackets in the queue.
    This routine will be useful if you want to cancel busy
    sends outside of halt handler for some reason.
        
Arguments:

    Adapter - pointer to our adapter context structure

Return Value:
    
--*/
{ 

⌨️ 快捷键说明

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