Exemplo n.º 1
0
VOID
BasePortFlushQueuedTxPackets(
    __in  PMP_PORT                Port
    )
{
    PMP_TX_MSDU                 currentPacket, packetListToComplete = NULL;
    ULONG                       count = 0;
    NDIS_STATUS                 completionStatus = BasePortGetPortStatus(Port);

    // Empty the pending TX queue
    MP_ACQUIRE_PORT_LOCK(Port, FALSE);
    while (!MpPacketQueueIsEmpty(&Port->PendingTxQueue))
    {
        currentPacket = MP_MSDU_FROM_QUEUE_ENTRY(MpDequeuePacket(&Port->PendingTxQueue));
        count++;

        MP_TX_MSDU_NEXT_MSDU(currentPacket) = NULL;
        MP_TX_MSDU_STATUS(currentPacket) = completionStatus;

        MP_TX_MSDU_NEXT_MSDU(currentPacket) = packetListToComplete;
        packetListToComplete = currentPacket;
    }
    MP_RELEASE_PORT_LOCK(Port, FALSE);

    if (packetListToComplete != NULL)
    {
        BasePortCompleteFailedPackets(Port, 
            packetListToComplete,
            0
            );
    }    
}
Exemplo n.º 2
0
VOID
BasePortFreeTranslatedTxPackets(
    __in  PMP_PORT                Port,
    __out PMP_TX_MSDU             PacketList
    )
{
    PMP_TX_MSDU                 currentPacket = PacketList;
    ULONG                       i = 0;

    while (currentPacket != NULL)
    {
        // Save the next since we are going to delete this packet
        PacketList = MP_TX_MSDU_NEXT_MSDU(currentPacket);

        // Delete the fragments from this packet
        for (i = 0; i < MP_TX_MSDU_MPDU_COUNT(currentPacket); i++)
        {
            NdisFreeToNPagedLookasideList(&(Port->TxFragmentLookaside), 
                MP_TX_MSDU_MPDU_AT(currentPacket, i));
        }

        // Delete the packet
        NdisFreeToNPagedLookasideList(&(Port->TxPacketLookaside), 
            currentPacket);
        
        currentPacket = PacketList;
    }
}
Exemplo n.º 3
0
/*
    NOTE
    This packet gives up the VNIC lock before calling into the hardware. The VNIC state might get
    changed during the course of the call
    */
VOID
VNicSendPktsToHw(    
    _In_ PVNIC                   pVNic,
    _In_ ULONG                   ulNumPkts,
    _In_ PMP_TX_MSDU             PacketList,
    _In_ ULONG                   SendFlags
    )
{
    BOOLEAN fDispatchLevel = SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? TRUE : FALSE;
    PMP_TX_MSDU currentPacket = NULL;
    ULONG myCount = 0;

    currentPacket = PacketList;
    while (currentPacket != NULL)
    {
        myCount++;
        currentPacket = MP_TX_MSDU_NEXT_MSDU(currentPacket);
    }
    MPASSERT(myCount == ulNumPkts);

    ASSERT(VNicIsLocked(pVNic));
    ASSERT(VNicIsActive(pVNic));
    
    MpTrace(COMP_HVL, DBG_LOUD, ("VNic(%d): Sending %d packets to the hardware \n", VNIC_PORT_NO, ulNumPkts));

    /*
        We can call the hardware for sending packets. We need to increment the context 
        switch ref count to avoid becoming inactive. The context switch ref count will be 
        decremented when we receive the send completionAlso we need to give up our lock 
        before calling the hardware. 
        */
    VNicIncCtxSRef(pVNic, ulNumPkts, REF_SEND_PKTS);

    // we also need to keep track of the sends outstanding to the hardware
    VNicIncOutstandingSends(pVNic, ulNumPkts);
    
    _Analysis_assume_lock_held_((& pVNic->Lock)->SpinLock);
    VNicUnlockAtDispatch(pVNic, fDispatchLevel);
    
    Hw11SendPackets(pVNic->pvHwContext, PacketList, SendFlags);

    VNicLockAtDispatch(pVNic, fDispatchLevel);
}
Exemplo n.º 4
0
VOID
VNic11SendPackets(
    __in PVNIC                   pVNic,
    __in PMP_TX_MSDU             PacketList,
    __in ULONG                   ulNumPkts,
    __in ULONG                   SendFlags
    )
{
    BOOLEAN fDispatchLevel = SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? TRUE : FALSE;
    BOOLEAN fFailSends = FALSE;
#if DBG
    PMP_TX_MSDU             currentPacket;
    ULONG                   myCount = 0;

    currentPacket = PacketList;
    while (currentPacket != NULL)
    {
        myCount++;
        currentPacket = MP_TX_MSDU_NEXT_MSDU(currentPacket);
    }

    MPASSERT(myCount == ulNumPkts);
#endif

    VNicLockAtDispatch(pVNic, fDispatchLevel);

    do
    {
        if (VNicIsInReset(pVNic))
        {
            MpTrace(COMP_HVL, DBG_NORMAL, ("VNIC(%d) is in reset. Failing %d sends. \n", VNIC_PORT_NO, ulNumPkts));
            fFailSends = TRUE;
            break;
        }
        
        if (VNicIsActive(pVNic) && Hw11CanTransmit(pVNic->pvHwContext) && (0 == PktQueueDepth(&pVNic->TxQueue)))
        {        
            VNicSendPktsToHw(pVNic, ulNumPkts, PacketList, SendFlags);
        }
        else
        {
            /*
                We are either 
                a. not currently active or 
                b. the packets cannot be submitted to the hardware or
                c. there are packets pending in the send queue already
                
                Queue the send requests internally
                */
            VNicQueueSendRequests(pVNic, ulNumPkts, PacketList);
        }
    } while (FALSE);
    
    VNicUnlockAtDispatch(pVNic, fDispatchLevel);

    if (fFailSends)
    {
        Port11SendCompletePackets(pVNic->pvPort, PacketList, SendFlags);
    }
    
    return;
}
Exemplo n.º 5
0
NDIS_STATUS
BasePortTranslateTxNBLsToTxPackets(
    __in  PMP_PORT                Port,
    __in  PNET_BUFFER_LIST        NetBufferLists,
    __out PMP_TX_MSDU  *          PacketList
    )
{
    PMP_TX_MSDU                 outputPacketList = NULL;
    PMP_TX_MSDU                 currentPacket, prevPacket = NULL;
    PMP_TX_MPDU                 currentFragment;
    USHORT                      fragmentIndex = 0;
    PNET_BUFFER_LIST            currentNetBufferList = NetBufferLists, nextNetBufferList;
    PNET_BUFFER                 currentNetBuffer;
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PDOT11_EXTSTA_SEND_CONTEXT  osSendContext, mySendContext;  // This is same for ExtAP & ExtSTA

    *PacketList = NULL;

    // Convert each NBL and NB to our structure    
    while (currentNetBufferList != NULL)
    {
        nextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList);

        // First the MP_TX_MSDU  
        currentPacket = NdisAllocateFromNPagedLookasideList(&(Port->TxPacketLookaside));
        if (currentPacket == NULL)
        {
            MpTrace(COMP_SEND, DBG_SERIOUS, ("Failed to allocate MP_TX_MSDU   for NET_BUFFER_LIST\n"));        
            ndisStatus = NDIS_STATUS_RESOURCES;
            break;
        }
        NdisZeroMemory(currentPacket, sizeof(MP_TX_MSDU  ));
        
        // Populate the TX_PACKET
        MP_TX_MSDU_WRAPPED_NBL(currentPacket) = currentNetBufferList;
        // Save the TX_MSDU in the NET_BUFFER_LIST for debugging purpose
        MP_NBL_WRAPPED_TX_MSDU(currentNetBufferList) = currentPacket;

        osSendContext = MP_GET_SEND_CONTEXT(currentNetBufferList);
        mySendContext = MP_TX_MSDU_SEND_CONTEXT(currentPacket);
        NdisMoveMemory(mySendContext, osSendContext, sizeof(DOT11_EXTSTA_SEND_CONTEXT));
        
        if (outputPacketList == NULL)
        {
            outputPacketList = currentPacket;
        }
        else
        {
            MP_TX_MSDU_NEXT_MSDU(prevPacket) = currentPacket;
        }
        // The Next NBL's PACKET would be added after the current NBL's PACKET
        prevPacket = currentPacket;

        // Now we go through the NBs in this NB
        fragmentIndex = 0;
        for (currentNetBuffer = NET_BUFFER_LIST_FIRST_NB(currentNetBufferList);
             currentNetBuffer != NULL;
             currentNetBuffer = NET_BUFFER_NEXT_NB(currentNetBuffer))
        {
            currentFragment = NdisAllocateFromNPagedLookasideList(&(Port->TxFragmentLookaside));
            if (currentFragment == NULL)
            {
                MpTrace(COMP_SEND, DBG_SERIOUS, ("Failed to allocate MP_TX_MPDU     for NET_BUFFER\n"));        
                ndisStatus = NDIS_STATUS_RESOURCES;
                break;
            }
            NdisZeroMemory(currentFragment, sizeof(MP_TX_MPDU    ));

            // Populate the TX_FRAGMENT
            MP_TX_MPDU_WRAPPED_NB(currentFragment) = currentNetBuffer;
            MP_TX_MPDU_MSDU(currentFragment) = currentPacket;

            // Add it to the fragment list of the packet
            MP_TX_MSDU_MPDU_AT(currentPacket, fragmentIndex) = currentFragment;
            fragmentIndex++;
        }
        MP_TX_MSDU_MPDU_COUNT(currentPacket) = fragmentIndex;        
        
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        
        currentNetBufferList = nextNetBufferList;
    }


    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        if (outputPacketList != NULL)
        {
            BasePortFreeTranslatedTxPackets(Port, outputPacketList);
            outputPacketList = NULL;
        }
    }

    *PacketList = outputPacketList;

    return ndisStatus;
}
Exemplo n.º 6
0
VOID
BasePortTransmitQueuedPackets(
    __in  PMP_PORT                Port,
    __in  ULONG                   SendFlags
    )
{
    PMP_TX_MSDU                 currentPacket, prevPacketToForward = NULL, packetListToForward = NULL;
    ULONG                       count = 0, numPktToFwd = 0;
    NDIS_STATUS                 ndisStatus;
    PMP_TX_MSDU                 packetListToFail = NULL;

    // PORT_LOCK must be held

    // If I am pausing, this flag is set. We would not
    // be processing any pending packets. These packets get flushed on a pause
    
    // then not process these pending packets
    if (MP_TEST_PORT_STATUS(Port, MP_PORT_CANNOT_SEND_MASK))
    {   
        //
        // We dont do anything
        //
        MpTrace(COMP_SEND, DBG_NORMAL, ("Dropping sends as port should not be sending\n"));                
        
        return;
    }

    while ((!MpPacketQueueIsEmpty(&Port->PendingTxQueue) &&
            (count < MAX_SEND_MSDU_TO_PROCESS)))
    {
        //
        // Dequeue the first packet from the list
        //
        currentPacket = MP_MSDU_FROM_QUEUE_ENTRY(MpDequeuePacket(&Port->PendingTxQueue));
        count++;

        // 
        // Let the port pre-process the packets. We only let one
        // packet to get processed at a time
        //
        MP_TX_MSDU_NEXT_MSDU(currentPacket) = NULL;
        MP_TX_MSDU_STATUS(currentPacket) = NDIS_STATUS_SUCCESS;
        ndisStatus = Port11NotifySend(Port, currentPacket, SendFlags);
        if (ndisStatus == NDIS_STATUS_SUCCESS)
        {
            //
            // Look at the per-packet status values
            //
            ndisStatus = MP_TX_MSDU_STATUS(currentPacket);
            if (ndisStatus == NDIS_STATUS_SUCCESS)
            {
                //
                // Port is fine with processing these packets. Let us check if we can
                // continue sending this down. We only check with the VNIC
                //
                if (VNic11CanTransmit(PORT_GET_VNIC(Port)) == FALSE)
                {
                    //
                    // Some reason we cannot submit this packet to the
                    // HW yet. Queue it in the pending Tx queue
                    //
                    ndisStatus = NDIS_STATUS_PENDING;

                    //
                    // In this case we indicate the packet to the Port again
                    // the next time we attempt to send. Ensure that the port
                    // can handle that
                    //
                }
            }
        }
        else
        {
            //
            // Port returned PENDING or FAILURE for the packet list. We wont
            // be sending any of these packets
            //
        }
        
        //
        // All the above processing would give us one of the following status codes
        //
        // NDIS_STATUS_SUCCESS - The packets can be processed furthers. In this case
        //                       we forward the packet to the lower layer
        // NDIS_STATUS_PENDING - This packet should not be sent now, but can be sent later
        //                       In this case we requeue the packet and stop processing
        //                       further packets
        // NDIS_STATUS_FAILURE or anything other failure status
        //                     - The packet is not sent and we continue processing
        //                       other packets
        if (ndisStatus == NDIS_STATUS_SUCCESS)
        {
            numPktToFwd++;
            
            // Add this to the end of the chain we are forwarding to the HW
            if (packetListToForward == NULL)
            {
                packetListToForward = currentPacket;
            }
            else
            {
                MP_TX_MSDU_NEXT_MSDU(prevPacketToForward) = currentPacket;
            }
            prevPacketToForward = currentPacket;

            //
            // Increment the counter for the number of packets we have submitted 
            // to the hardware. This would block the port from pausing, etc
            //
            PORT_INCREMENT_PNP_REFCOUNT(Port);
        }
        else if (ndisStatus == NDIS_STATUS_PENDING)
        {
            //
            // Put the packet back at the head of the packet queue. To avoid out of
            // order delivery we dont go forward and give any more packets to the 
            // lower layer 
            //
            MpQueuePacketPriority(&Port->PendingTxQueue, QUEUE_ENTRY_FROM_MP_MSDU(currentPacket));
            break;
        }
        else
        {
            //
            // Put this packet in the list of packets to be failed
            //
            MpTrace(COMP_SEND, DBG_NORMAL, ("Port or VNic failed sends with status 0x%08x\n", ndisStatus));
            MP_TX_MSDU_STATUS(currentPacket) = ndisStatus;
            MP_TX_MSDU_NEXT_MSDU(currentPacket) = packetListToFail;
            packetListToFail = currentPacket;
        }

    }

    if ((packetListToForward != NULL) || (packetListToFail != NULL))
    {
        // Forward this list to the VNIC
        MP_RELEASE_PORT_LOCK(Port, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags));
        if (packetListToForward != NULL)
        {
            VNic11SendPackets(PORT_GET_VNIC(Port), packetListToForward, numPktToFwd, SendFlags);
        }
        
        //
        // Complete the failed packets
        //
        if (packetListToFail != NULL)
        {
            BasePortCompleteFailedPackets(Port, 
                packetListToFail,
                NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0
                );
        }
        
        MP_ACQUIRE_PORT_LOCK(Port, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags));
    }
}
Exemplo n.º 7
0
VOID
BasePortCompleteFailedPackets(
    __in  PMP_PORT                Port,
    __in  PMP_TX_MSDU             PacketList,
    __in  ULONG                   SendCompleteFlags
    )
{
    PMP_TX_MSDU                 currentPacket = PacketList;
    PNET_BUFFER_LIST            currentNetBufferList, prevNetBufferList = NULL;
    PNET_BUFFER_LIST            netBufferListsToComplete = NULL;
    #if DBG
    ULONG ulNumNBLs = 0, ulInternalSends = 0;
    #endif
        

    while (currentPacket != NULL)
    {        
        //
        // No refcount is added yet, so we dont need to remove anything
        //

        if (MP_TX_MSDU_WRAPPED_NBL(currentPacket) == NULL)
        {
            #if DBG
            ulInternalSends++;
            #endif
            // Internal packet submitted from BasePortSendInternalPacket, free the memory
            // we allocated for the buffer
            MP_FREE_MEMORY(MP_TX_MSDU_MPDU_AT(currentPacket, 0)->InternalSendBuffer);
        }
        else
        {
            #if DBG
            ulNumNBLs++;
            #endif
            //
            // There were from the OS. We need to convert back to NBLs and 
            // complete them to the OS
            //

            //
            // Get the NBLs out
            //
            currentNetBufferList = currentPacket->NetBufferList;
            NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList) = NULL;
            NET_BUFFER_LIST_STATUS(currentNetBufferList) = currentPacket->Status;

            if (netBufferListsToComplete == NULL)
            {
                netBufferListsToComplete = currentNetBufferList;
            }
            else
            {
                NET_BUFFER_LIST_NEXT_NBL(prevNetBufferList) = currentNetBufferList;
            }
            
            prevNetBufferList = currentNetBufferList;
        }

        currentPacket = MP_TX_MSDU_NEXT_MSDU(currentPacket);
    }

    //
    // Free our packet wrapper structures for all the packets
    //
    BasePortFreeTranslatedTxPackets(Port, PacketList);

    #if DBG
        MpTrace(COMP_SEND, DBG_NORMAL, ("Port(%d): NdisMSendNetBufferListsComplete called with %d NBLs\n", Port->PortNumber, ulNumNBLs));
        MpTrace(COMP_SEND, DBG_NORMAL, ("Port(%d): Completed %d internal sends\n", Port->PortNumber, ulInternalSends));
    #endif        

    if (netBufferListsToComplete != NULL)
    {
        // Complete the NBLs back to NDIS
        NdisMSendNetBufferListsComplete(
            Port->MiniportAdapterHandle,
            netBufferListsToComplete,
            SendCompleteFlags
            );
    }
}