예제 #1
0
파일: tcbrcb.c 프로젝트: kcrazy/winekit
VOID
ReturnTCB(
    __in  PMP_ADAPTER  Adapter,
    __in  PTCB         Tcb)
{
    TXNblRelease(Adapter, NBL_FROM_SEND_NB(Tcb->NetBuffer), TRUE);
    Tcb->NetBuffer = NULL;

    NdisInterlockedInsertTailList(
            &Adapter->FreeTcbList,
            &Tcb->TcbLink,
            &Adapter->FreeTcbListLock);
}
예제 #2
0
VOID
MPSendNetBufferLists(
    _In_  NDIS_HANDLE             MiniportAdapterContext,
    _In_  PNET_BUFFER_LIST        NetBufferLists,
    _In_  NDIS_PORT_NUMBER        PortNumber,
    _In_  ULONG                   SendFlags)
/*++

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
    NetBufferLists              Head of a list of NBLs to send
    PortNumber                  A miniport adapter port.  Default is 0.
    SendFlags                   Additional flags for the send operation

Return Value:

    None.  Write status directly into each NBL with the NET_BUFFER_LIST_STATUS
    macro.

--*/
{
    PMP_ADAPTER       Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
    PNET_BUFFER_LIST  Nbl;
    PNET_BUFFER_LIST  NextNbl = NULL;
    BOOLEAN           fAtDispatch = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL) ? TRUE:FALSE;
    NDIS_STATUS       Status;
    ULONG             NumNbls=0;

    DEBUGP(MP_TRACE, "[%p] ---> MPSendNetBufferLists\n", Adapter);

    UNREFERENCED_PARAMETER(PortNumber);
    UNREFERENCED_PARAMETER(SendFlags);
    ASSERT(PortNumber == 0); // Only the default port is supported


    //
    // Each NET_BUFFER_LIST has a list of NET_BUFFERs.
    // Loop over all the NET_BUFFER_LISTs, sending each NET_BUFFER.
    //
    for (
        Nbl = NetBufferLists;
        Nbl!= NULL;
        Nbl = NextNbl, ++NumNbls)
    {
        PNET_BUFFER NetBuffer;

        NextNbl = NET_BUFFER_LIST_NEXT_NBL(Nbl);

        //
        // Unlink the NBL and prepare our bookkeeping.
        //
        // We use a reference count to make sure that we don't send complete
        // the NBL until we're done reading each NB on the NBL.
        //
        NET_BUFFER_LIST_NEXT_NBL(Nbl) = NULL;
        SEND_REF_FROM_NBL(Nbl) = 0;

        Status = TXNblReference(Adapter, Nbl);

        if(Status == NDIS_STATUS_SUCCESS)
        {
            NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_SUCCESS;

            //
            // Queue each NB for transmission.
            //
            for (
                NetBuffer = NET_BUFFER_LIST_FIRST_NB(Nbl);
                NetBuffer != NULL;
                NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer))
            {
                NBL_FROM_SEND_NB(NetBuffer) = Nbl;
                TXQueueNetBufferForSend(Adapter, NetBuffer);
            }

            TXNblRelease(Adapter, Nbl, fAtDispatch);
        }
        else
        {
            //
            // We can't send this NBL now.  Indicate failure.
            //
            if (MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS))
            {
                NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_RESET_IN_PROGRESS;
            }
            else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS|fMP_ADAPTER_PAUSED))
            {
                NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_PAUSED;
            }
            else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LOW_POWER))
            {
                NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_LOW_POWER_STATE;
            }
            else
            {
                NET_BUFFER_LIST_STATUS(Nbl) = Status;
            }

            NdisMSendNetBufferListsComplete(
                    Adapter->AdapterHandle,
                    Nbl,
                    fAtDispatch ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0);

            continue;
        }
    }

    DEBUGP(MP_TRACE, "[%p] %i NBLs processed.\n", Adapter, NumNbls);

    //
    // Now actually go send each of the queued NBs.
    //
    TXTransmitQueuedSends(Adapter, fAtDispatch);

    DEBUGP(MP_TRACE, "[%p] <--- MPSendNetBufferLists\n", Adapter);
}
예제 #3
0
VOID
TXFlushSendQueue(
    _In_  PMP_ADAPTER  Adapter,
    _In_  NDIS_STATUS  CompleteStatus)
/*++

Routine Description:

    This routine is called by the Halt or Reset handler to fail all
    the queued up Send NBLs because the device is either gone, being
    stopped for resource rebalance, or reset.

Arguments:

    Adapter                     Pointer to our adapter
    CompleteStatus              The status code with which to complete each NBL

Return Value:

    None.

--*/
{
    PTCB Tcb;

    DEBUGP(MP_TRACE, "[%p] ---> TXFlushSendQueue Status = 0x%08x\n", Adapter, CompleteStatus);


    //
    // First, free anything queued in the driver.
    //

    while (TRUE)
    {
        PLIST_ENTRY pEntry;
        PNET_BUFFER NetBuffer;
        PNET_BUFFER_LIST NetBufferList;

        pEntry = NdisInterlockedRemoveHeadList(
                &Adapter->SendWaitList,
                &Adapter->SendWaitListLock);

        if (!pEntry)
        {
            // End of list -- nothing left to free.
            break;
        }

        NetBuffer = NB_FROM_SEND_WAIT_LIST(pEntry);
        NetBufferList = NBL_FROM_SEND_NB(NetBuffer);

        DEBUGP(MP_TRACE, "[%p] Dropping Send NB: 0x%p.\n", Adapter, NetBuffer);

        NET_BUFFER_LIST_STATUS(NetBufferList) = CompleteStatus;
        TXNblRelease(Adapter, NetBufferList, FALSE);
    }


    //
    // Next, cancel anything queued in the hardware.
    //

    while (NULL != (Tcb = TXGetNextTcbToSend(Adapter)))
    {
        NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(Tcb->NetBuffer)) = CompleteStatus;
        ReturnTCB(Adapter, Tcb);
    }


    DEBUGP(MP_TRACE, "[%p] <--- TXFlushSendQueue\n", Adapter);
}
예제 #4
0
VOID
TXSendComplete(
    _In_ PMP_ADAPTER Adapter)
/*++

Routine Description:

    This routine completes pending sends for the given adapter.

    Each busy TCB is popped from the BusyTcbList and its corresponding NB is
    released.  If there was an error sending the frame, the NB's NBL's status
    is updated.

--*/
{
    BOOLEAN fRescheduleThisDpcAgain = TRUE;
    ULONG NumFramesSent = 0;

    DEBUGP(MP_TRACE, "[%p] ---> TXSendComplete.\n", Adapter);

    for (NumFramesSent = 0; NumFramesSent < NIC_MAX_SENDS_PER_DPC; NumFramesSent++)
    {
        ULONG BytesSent;

        PTCB Tcb = TXGetNextTcbToSend(Adapter);
        if (!Tcb)
        {
            //
            // There are no more TCBs remaining to send.  We're all done.
            //
            fRescheduleThisDpcAgain = FALSE;
            break;
        }


        //
        // Finish the transmit operation.  For our hardware, that means the
        // frame is pushed onto the RecvWaitLists of each other adapter.
        //

        BytesSent = HWGetBytesSent(Adapter, Tcb);

        if (BytesSent == 0)
        {
            //
            // Failed to send the frame.
            //

            Adapter->TransmitFailuresOther++;
            NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(Tcb->NetBuffer)) = NDIS_STATUS_RESOURCES;
        }
        else
        {
            //
            // We've finished sending this NB successfully; update the stats.
            //
            switch (Tcb->FrameType)
            {
                case NDIS_PACKET_TYPE_BROADCAST:
                    Adapter->FramesTxBroadcast++;
                    Adapter->BytesTxBroadcast += BytesSent;
                    break;

                case NDIS_PACKET_TYPE_MULTICAST:
                    Adapter->FramesTxMulticast++;
                    Adapter->BytesTxMulticast += BytesSent;
                    break;

                case NDIS_PACKET_TYPE_DIRECTED:
                default:
                    Adapter->FramesTxDirected++;
                    Adapter->BytesTxDirected += BytesSent;
            }
        }


        //
        // Now that we've finished using the TCB and its associated NET_BUFFER,
        // we can release the NET_BUFFER back to the protocol and the TCB back
        // to the free list.
        //
        ReturnTCB(Adapter, Tcb);
    }

    TXTransmitQueuedSends(Adapter, TRUE);

    if (fRescheduleThisDpcAgain)
    {
        TXScheduleTheSendComplete(Adapter);
    }

    DEBUGP(MP_TRACE, "[%p] <--- TXSendComplete.\n", Adapter);
}
예제 #5
0
VOID
TXQueueNetBufferForSend(
    _In_  PMP_ADAPTER       Adapter,
    _In_  PNET_BUFFER       NetBuffer)
/*++

Routine Description:

    This routine inserts the NET_BUFFER into the SendWaitList, then calls
    TXTransmitQueuedSends to start sending data from the list.

    We use this indirect queue to send data because the miniport should try to
    send frames in the order in which the protocol gave them.  If we just sent
    the NET_BUFFER immediately, then it would be out-of-order with any data on
    the SendWaitList.


    Runs at IRQL <= DISPATCH_LEVEL

Arguments:

    Adapter                     Adapter that is transmitting this NB
    NetBuffer                   NB to be transfered

Return Value:

    None.

--*/
{
    NDIS_STATUS       Status;
    UCHAR             DestAddress[NIC_MACADDR_SIZE];

    DEBUGP(MP_TRACE, "[%p] ---> TXQueueNetBufferForSend, NB= 0x%p\n", Adapter, NetBuffer);

    do
    {
        //
        // First, do a sanity check on the frame data.
        //
        Status = HWGetDestinationAddress(NetBuffer, DestAddress);
        if (Status != NDIS_STATUS_SUCCESS)
        {
            NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(NetBuffer)) = NDIS_STATUS_INVALID_DATA;
            break;
        }

        //
        // Stash away the frame type.  We'll use that later, when updating
        // our send statistics (since we don't have NIC hardware to compute the
        // send statistics for us).
        //
        FRAME_TYPE_FROM_SEND_NB(NetBuffer) = NICGetFrameTypeFromDestination(DestAddress);

        //
        // Pin the original NBL with a reference, so it isn't completed until
        // we're done with its NB.
        //
        Status = TXNblReference(Adapter, NBL_FROM_SEND_NB(NetBuffer));
        if(Status == NDIS_STATUS_SUCCESS)
        {
            //
            // Insert the NB into the queue.  The caller will flush the queue when
            // it's done adding items to the queue.
            //
            NdisInterlockedInsertTailList(
                    &Adapter->SendWaitList,
                    SEND_WAIT_LIST_FROM_NB(NetBuffer),
                    &Adapter->SendWaitListLock);
        }

    } while (FALSE);


    DEBUGP(MP_TRACE, "[%p] <--- TXQueueNetBufferForSend\n", Adapter);
}