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

📄 offload.c

📁 Intel EtherExpressTM PRO/100+ Ethernet 网卡在Windows2000/xp下的PCI驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
            return;
        }
        
        //
        // Adapter is not ready and there is not link
        //
        Status = MP_GET_STATUS_FROM_FLAGS(Adapter);

        NdisReleaseSpinLock(&Adapter->SendLock);

        for (PacketCount = 0; PacketCount < NumOfPackets; PacketCount++)
        {
            NdisMSendComplete(
                MP_GET_ADAPTER_HANDLE(Adapter),
                PacketArray[PacketCount],
                Status);
        }

        return;
    }

    //
    // Adapter is ready, send these packets      
    //
    for (PacketCount = 0; PacketCount < NumOfPackets; PacketCount++)
    {
        //
        // queue is not empty or tcb is not available 
        //
        if (!IsQueueEmpty(&Adapter->SendWaitQueue) || 
            !MP_TCB_RESOURCES_AVAIABLE(Adapter) ||
            MP_TEST_FLAG(Adapter, fMP_SHARED_MEM_IN_USE))
        {
            InsertTailQueue(&Adapter->SendWaitQueue, 
                            MP_GET_PACKET_MR( PacketArray[PacketCount] )
                           );
            Adapter->nWaitSend++;
        }
        else
        {
            MpOffloadSendPacket(Adapter, PacketArray[PacketCount], FALSE);
        }
    }

    NdisReleaseSpinLock(&Adapter->SendLock);

    DBGPRINT(MP_TRACE, ("<==== MPOffloadSendPackets\n"));

    return;
}

/*++
Routine Description:

    Do the work to send a packet
    Assumption: Send spinlock has been acquired and shared mem is available 

Arguments:

    Adapter     Pointer to our adapter
    Packet      The packet
    bFromQueue  TRUE if it's taken from the send wait queue

Return Value:

    NDIS_STATUS_SUCCESS
    NDIS_STATUS_PENDING         Put into the send wait queue
    NDIS_STATUS_HARD_ERRORS

--*/
NDIS_STATUS MpOffloadSendPacket(
    IN  PMP_ADAPTER   Adapter,
    IN  PNDIS_PACKET  Packet,
    IN  BOOLEAN       bFromQueue
    )
{
    NDIS_STATUS             Status = NDIS_STATUS_PENDING;
    PMP_TCB                 pMpTcb = NULL;
    ULONG                   BytesCopied;
    ULONG                   NumOfPackets;

    // Mimiced frag list if the packet is too small or too fragmented.                                         
    MP_FRAG_LIST            FragList;
    
    // Pointer to either the scatter gather or the local mimiced frag list
    PMP_FRAG_LIST           pFragList;
    NDIS_PHYSICAL_ADDRESS   SendPa;
    ULONG                   BytesToCopy;
    ULONG                   Offset;
    PNDIS_PACKET_EXTENSION  PktExt;
    ULONG                   mss;
    PNDIS_BUFFER            NdisBuffer;
    ULONG                   PacketLength;
    PVOID                   CopyStartVa;
    ULONG                   IpHdrOffset;
    PUCHAR                  StartVa;
    PNDIS_BUFFER            FirstBuffer;
    
    DBGPRINT(MP_TRACE, ("--> MpOffloadSendPacket, Pkt= "PTR_FORMAT"\n", Packet));

    //
    //Check is shared memory available,  just double check
    //
    if (MP_TEST_FLAG(Adapter, fMP_SHARED_MEM_IN_USE))
    {
        DBGPRINT(MP_WARN, ("Shared mem is in use.\n"));
        if (bFromQueue)
        {
            InsertHeadQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(Packet));
        }
        else
        {
            InsertTailQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(Packet));
        }
        DBGPRINT(MP_TRACE, ("<-- MpOffloadSendPacket\n"));
        return Status;
    }

    MP_SET_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
    ASSERT(Adapter->SharedMemRefCount == 0);
    //
    // Get maximum segment size
    // 
    PktExt = NDIS_PACKET_EXTENSION_FROM_PACKET(Packet);       
    mss = PtrToUlong(PktExt->NdisPacketInfo[TcpLargeSendPacketInfo]);
    
    //
    // Copy NIC_MAX_PACKET_SIZE bytes of data from NDIS buffer 
    // to the shared memory
    //
    NdisQueryPacket( Packet, NULL, NULL, &FirstBuffer, (PUINT)&PacketLength );
    Offset = 0;
    NdisBuffer = FirstBuffer;
    BytesToCopy = NIC_MAX_PACKET_SIZE;
    CopyStartVa = Adapter->OffloadSharedMem.StartVa;
    BytesCopied = MpCopyData(BytesToCopy, &NdisBuffer, CopyStartVa, &Offset, 0); 

    //
    // MpCopyPacket may return 0 if system resources are low or exhausted
    //
    if (BytesCopied == 0)
    {
        
        DBGPRINT(MP_ERROR, ("Calling NdisMSendComplete with NDIS_STATUS_RESOURCES, Pkt= "PTR_FORMAT"\n", Packet));
    
        NdisReleaseSpinLock(&Adapter->SendLock); 
        NdisMSendComplete(
                MP_GET_ADAPTER_HANDLE(Adapter),
                Packet,
                NDIS_STATUS_RESOURCES);
    
        NdisAcquireSpinLock(&Adapter->SendLock);    
        MP_CLEAR_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
            
        return NDIS_STATUS_RESOURCES;            
    }

    StartVa = CopyStartVa;
    SendPa = Adapter->OffloadSharedMem.PhyAddr;
    IpHdrOffset = Adapter->EncapsulationFormat.EncapsulationHeaderSize;
    
    // 
    // Check if large send capability is on and this is a large packet
    // 
    if (Adapter->NicTaskOffload.LargeSendOffload && mss > 0)
    {
        ULONG                IpHeaderLen;
        ULONG                TcpHdrOffset;
        ULONG                HeadersLen;
        IPHeader UNALIGNED  *IpHdr;
        TCPHeader UNALIGNED *TcpHdr;
        ULONG                TcpDataLen;
        ULONG                LastPacketDataLen;
        int                  SeqNum;
        ULONG                TmpXsum;
        ULONG                BytesSent = 0;
        ULONG                TmpPxsum = 0;
        USHORT               TcpHeaderLen;
        USHORT               IpSegmentLen;
        BOOLEAN              IsFinSet = FALSE;
        BOOLEAN              IsPushSet = FALSE;
        BOOLEAN              IsFirstSlot = TRUE;
        
        

        IpHdr = (IPHeader UNALIGNED*)((PUCHAR)CopyStartVa + IpHdrOffset);
        IpHeaderLen = IP_HEADER_LENGTH(IpHdr);
        
        // 
        // The packet must be a TCP packet
        //
        ASSERT(IpHdr->iph_protocol == PROTOCOL_TCP);
        
        TcpHdrOffset = IpHdrOffset + IpHeaderLen;
        
        TcpHdr = (TCPHeader UNALIGNED *)((PUCHAR)CopyStartVa + TcpHdrOffset);
        
        TcpHeaderLen = TCP_HEADER_LENGTH(TcpHdr);
        HeadersLen = TcpHdrOffset + TcpHeaderLen;
       
        //
        // This length include IP, TCP headers and TCP data.
        //
        IpSegmentLen = net_short(IpHdr->iph_length);

        //
        // get the pseudo-header 1's complement sum
        //
        TmpPxsum = TcpHdr->tcp_xsum;
        
        ASSERT(IpSegmentLen == PacketLength - IpHdrOffset);
        
        IsFinSet = (BOOLEAN)(TcpHdr->tcp_flags & TCP_FLAG_FIN);
        IsPushSet = (BOOLEAN)(TcpHdr->tcp_flags & TCP_FLAG_PUSH);
        
        SeqNum = net_long(TcpHdr->tcp_seq);
        TcpDataLen = IpSegmentLen - TcpHeaderLen - IpHeaderLen;

        ASSERT(TcpDataLen <= Adapter->LargeSendInfo.MaxOffLoadSize)
        
        NumOfPackets = TcpDataLen / mss + 1;
        
        ASSERT (NumOfPackets >= Adapter->LargeSendInfo.MinSegmentCount);
        
        LastPacketDataLen = TcpDataLen % mss;
        NdisBuffer = FirstBuffer;
        BytesSent = 0;

        //
        // The next copy start with offset of (mss+HeadersLen) corresponding to first buf
        // 
        BytesCopied = (BytesCopied >= mss + HeadersLen)? (mss + HeadersLen):BytesCopied;
        Offset = BytesCopied;

        //
        // Send out all the packets from the large TCP packet
        // 
        while (NumOfPackets--)
        {
            TmpXsum = 0;
           
            //
            // Is the first packet?
            // 
            if (IsFirstSlot) 
            {
                if (NumOfPackets == 0)
                {
                    PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(BytesCopied);
                }
                else 
                {
                    if (IsFinSet)
                    {
                        TcpHdr->tcp_flags &= ~TCP_FLAG_FIN;
                        
                    }
                    if (IsPushSet)
                    {                        
                        TcpHdr->tcp_flags &= ~TCP_FLAG_PUSH;
                        
                    }
                        
                }
                BytesCopied -= HeadersLen;
                IsFirstSlot = FALSE;
            }
            //
            // Not the first packet
            // 
            else
            {
                //
                // copy headers
                //
                NdisMoveMemory (StartVa, CopyStartVa, HeadersLen);
                
                IpHdr = (IPHeader UNALIGNED *)((PUCHAR)StartVa + IpHdrOffset);
                TcpHdr = (TCPHeader UNALIGNED *) ((PUCHAR)StartVa + TcpHdrOffset);
                
                //
                // Last packet
                //
                if (NumOfPackets == 0)
                {
                    BytesToCopy = LastPacketDataLen;
                    PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = 
                                                   UlongToPtr(BytesSent + LastPacketDataLen);
                }
                else 
                {
                    BytesToCopy = mss;
                    // clear flag
                    if (IsFinSet)
                    {
                        TcpHdr->tcp_flags &= ~TCP_FLAG_FIN;
                    }
                    if (IsPushSet)
                    {
                        TcpHdr->tcp_flags &= ~TCP_FLAG_PUSH;
                    }
                    
                }
                BytesCopied = MpCopyData(
                                    BytesToCopy,        
                                    &NdisBuffer, 
                                    StartVa + HeadersLen, 
                                    &Offset,
                                    HeadersLen);
                
                //
                // MpCopyData may return 0 if system resources are low or exhausted
                //
                if (BytesCopied == 0)
                {
        
                    PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(BytesSent);
                    return NDIS_STATUS_RESOURCES;            
                }
            } 
            
            IpHdr->iph_length = net_short(TcpHeaderLen + IpHeaderLen + BytesCopied);
            TcpHdr->tcp_seq = net_long(SeqNum);
            SeqNum += BytesCopied;

            //
            // calculate ip checksum and tcp checksum
            //
            IpHdr->iph_xsum = 0;
            XSUM(TmpXsum, StartVa, IpHeaderLen, IpHdrOffset);
            IpHdr->iph_xsum = ~(USHORT)(TmpXsum);

            TmpXsum = TmpPxsum + net_short((USHORT)(BytesCopied + TcpHeaderLen));
            TcpHdr->tcp_xsum = 0;
            XSUM(TmpXsum, StartVa, BytesCopied + TcpHeaderLen, TcpHdrOffset);
            TcpHdr->tcp_xsum = ~(USHORT)(TmpXsum);

            BytesSent += BytesCopied;
            BytesCopied += HeadersLen;
            
            //
            // get TCB for the slot
            //
            pMpTcb = Adapter->CurrSendTail;
            ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
            
            //
            // Set up the frag list, only one fragment after it's coalesced
            //
            pFragList = &FragList;
            pFragList->NumberOfElements = 1;
            pFragList->Elements[0].Address = SendPa;
            pFragList->Elements[0].Length = (BytesCopied >= NIC_MIN_PACKET_SIZE) ?
                                             BytesCopied : NIC_MIN_PACKET_SIZE;
            pMpTcb->Packet = Packet;
                
            MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);
            
            //
            // Call the NIC specific send handler, it only needs to deal with the frag list
            //
            Status = NICSendPacket(Adapter, pMpTcb, pFragList);
                
            Adapter->nBusySend++;
            Adapter->SharedMemRefCount++;
       
            //
            // Update the CopyVa and SendPa
            //
            SendPa.QuadPart += BytesCopied;
            StartVa += BytesCopied;
            
            Adapter->CurrSendTail = Adapter->CurrSendTail->Next;
            
            //
            // out of resouces, which will send complete part of the packet
            //
            if (Adapter->nBusySend >= Adapter->NumTcb)
            {
                PktExt->NdisPacketInfo[TcpLargeSendPacketInfo] = UlongToPtr(BytesSent);
                break;
            }
        } // while
    }
    // 
    // This is not a large packet or large send capability is not on
    //
    else
    {
        //
        // get TCB for the slot
        //
        pMpTcb = Adapter->CurrSendTail;
        ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
        //
        // Set up the frag list, only one fragment after it's coalesced
        //
        pFragList = &FragList;
        pFragList->NumberOfElements = 1;
        pFragList->Elements[0].Address = SendPa;
        pFragList->Elements[0].Length = (BytesCopied >= NIC_MIN_PACKET_SIZE) ?
                                         BytesCopied : NIC_MIN_PACKET_SIZE;
        pMpTcb->Packet = Packet;

        if (Adapter->NicChecksumOffload.DoXmitTcpChecksum
            && Adapter->NicTaskOffload.ChecksumOffload)
        {
            CalculateChecksum(CopyStartVa, 
                                  BytesCopied,
                                  Packet, 
                                  Adapter->EncapsulationFormat.EncapsulationHeaderSize);
        }
        MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);
        //
        // Call the NIC specific send handler, it only needs to deal with the frag list
        //
        Status = NICSendPacket(Adapter, pMpTcb, pFragList);

        Adapter->nBusySend++;
        Adapter->SharedMemRefCount++;
        
        ASSERT(Adapter->nBusySend <= Adapter->NumTcb);
        Adapter->CurrSendTail = Adapter->CurrSendTail->Next;
        
    }
    
    DBGPRINT(MP_TRACE, ("<-- MpOffloadSendPacket\n"));
    return Status;
}  



/*++
Routine Description:

    Recycle a MP_TCB and complete the packet if necessary
    Assumption: Send spinlock has been acquired 

Arguments:

    Adapter     Pointer to our adapter
    pMpTcb      Pointer to MP_TCB        

Return Value:

    None

--*/
VOID MP_OFFLOAD_FREE_SEND_PACKET(
    IN  PMP_ADAPTER  Adapter,
    IN  PMP_TCB      pMpTcb
    )
{
    
    PNDIS_PACKET      Packet;
    
    ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));

    Packet = pMpTcb->Packet;
    pMpTcb->Packet = NULL;
    pMpTcb->Count = 0;

    MP_CLEAR_FLAGS(pMpTcb);

    Adapter->CurrSendHead = Adapter->CurrSendHead->Next;
    Adapter->nBusySend--;
    
    Adapter->SharedMemRefCount--;

    if (Adapter->SharedMemRefCount == 0)
    {
        MP_CLEAR_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
        //
        // Send complete the packet too
        //
        NdisMSendComplete(
                        MP_GET_ADAPTER_HANDLE(Adapter),
                        Packet,
                        NDIS_STATUS_SUCCESS);
        
        ASSERT(Adapter->nBusySend == 0);
    }
    ASSERT(Adapter->nBusySend >= 0);

}

    

/*++
Routine Description:

    Disable the existing capabilities before protocol is setting the
    new capabilities

Arguments:

    Adapter     Pointer to our adapter

Return Value:

    None

--*/
VOID DisableOffload(
    IN PMP_ADAPTER Adapter
    )
{
    //
    // Disable the capabilities of the miniports
    // 
    NdisZeroMemory(&(Adapter->NicTaskOffload), sizeof(NIC_TASK_OFFLOAD));
    NdisZeroMemory(&(Adapter->NicChecksumOffload), sizeof(NIC_CHECKSUM_OFFLOAD));
}

#endif // OFFLOAD
            

⌨️ 快捷键说明

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