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

📄 offload.c

📁 Intel EtherExpressTM PRO/100+ Ethernet 网卡在Windows2000/xp下的PCI驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

Copyright (c) 2001 Microsoft Corporation

Module Name:

   Offload.c

Abstract:
   This file contains all the functions needed by TCP/IP checksum and segmentation
   of Large TCP packets task offloading. Actually thses functions should be 
   implemented by hardware, and the purpose of this file is just to demonstrate 
   how to use OID_TCP_TASK_OFFLOAD to enable/disable task offload capabilities.

Revision History
   Who           When                What
   ------        ---------           ----------
                 02-19-2001          Create
                 
Notes:

--*/

#include "precomp.h"

#if DBG
#define _FILENUMBER     'DLFO'
#endif

#ifdef OFFLOAD

#define PROTOCOL_TCP         6

//
// This miniport uses shared memory to handle offload tasks, so it tries to allocate
// shared memory of 64K, 32K, 16K. First it tries to allocate 64K, if fails, then
// it tries 32K and so on. If successed, than keeps the size in adapter, which is used
// to decide the maximum offload size in large send. If all the tries fail, then this
// miniport cann't support any offload task.
// 
ULONG LargeSendSharedMemArray[LARGE_SEND_MEM_SIZE_OPTION] = {64*1024, 32*1024, 16*1024};

//
// if x is aabb(where aa, bb are hex bytes), we want net_short (x) to be bbaa.
// 
USHORT net_short(
    ULONG NaturalData
    )
{
    USHORT ShortData = (USHORT)NaturalData;

    return (ShortData << 8) | (ShortData >> 8);
}

//
// if x is aabbccdd (where aa, bb, cc, dd are hex bytes)
// we want net_long(x) to be ddccbbaa.  A small and fast way to do this is
// to first byteswap it to get bbaaddcc and then swap high and low words.
//
ULONG net_long(
    ULONG NaturalData
    )
{
    ULONG ByteSwapped;

    ByteSwapped = ((NaturalData & 0x00ff00ff) << 8) |
                  ((NaturalData & 0xff00ff00) >> 8);

    return (ByteSwapped << 16) | (ByteSwapped >> 16);
}


//
// calculate the checksum for pseudo-header
//
#define PHXSUM(s,d,p,l) (UINT)( (UINT)*(USHORT *)&(s) + \
                        (UINT)*(USHORT *)((char *)&(s) + sizeof(USHORT)) + \
                        (UINT)*(USHORT *)&(d) + \
                        (UINT)*(USHORT *)((char *)&(d) + sizeof(USHORT)) + \
                        (UINT)((USHORT)net_short((p))) + \
                        (UINT)((USHORT)net_short((USHORT)(l))) )


#define IP_HEADER_LENGTH(pIpHdr)   \
        ( (ULONG)((pIpHdr->iph_verlen & 0x0F) << 2) )

#define TCP_HEADER_LENGTH(pTcpHdr) \
        ( (USHORT)(((*((PUCHAR)(&(pTcpHdr->tcp_flags))) & 0xF0) >> 4) << 2) )


/*++
Routine Description:
    
   Copy data in a packet to the specified location 
    
Arguments:
    
    BytesToCopy          The number of bytes need to copy
    CurreentBuffer       The buffer to start to copy
    StartVa              The start address to copy the data to
    Offset               The start offset in the buffer to copy the data
    HeandersLength       The length of the headers which have aleady been copied.

Return Value:
 
    The number of bytes actually copied
  

--*/  

ULONG MpCopyData(
    IN  ULONG           BytesToCopy, 
    IN  PNDIS_BUFFER*   CurrentBuffer, 
    IN  PVOID           StartVa, 
    IN  PULONG          Offset,
    IN  ULONG           HeadersLength
    )
{
    ULONG    CurrLength;
    PUCHAR   pSrc;
    PUCHAR   pDest;
    ULONG    BytesCopied = 0;
    ULONG    CopyLength;
    
    DBGPRINT(MP_TRACE, ("--> MpCopyData\n"));
    pDest = StartVa;
    while (*CurrentBuffer && BytesToCopy != 0)
    {
        //
        // Even the driver is 5.0, it should use safe APIs
        //
        NdisQueryBufferSafe(
            *CurrentBuffer, 
            &pSrc,
            (PUINT)&CurrLength,
            NormalPagePriority);
        if (pSrc == NULL)
        {
            BytesCopied = 0;
            break;
        }
        // 
        //  Current buffer length is greater than the offset to the buffer
        //  
        if (CurrLength > *Offset)
        { 
            pSrc += *Offset;
            CurrLength -= *Offset;
            CopyLength = CurrLength > BytesToCopy ? BytesToCopy : CurrLength;
            
            NdisMoveMemory(pDest, pSrc, CopyLength);
            BytesCopied += CopyLength;

            if (CurrLength > BytesToCopy)
            {
                *Offset += BytesToCopy;
                break;
            }

            BytesToCopy -= CopyLength;
            pDest += CopyLength;
            *Offset = 0;
        }
        else
        {
            *Offset -= CurrLength;
        }
        NdisGetNextBuffer( *CurrentBuffer, CurrentBuffer);
    
    }
    ASSERT(BytesCopied <= NIC_MAX_PACKET_SIZE);
    if (BytesCopied + HeadersLength < NIC_MIN_PACKET_SIZE)
    {
        NdisZeroMemory(pDest, NIC_MIN_PACKET_SIZE - (BytesCopied + HeadersLength));
    }
    
    DBGPRINT(MP_TRACE, ("<-- MpCopyData\n"));
    return BytesCopied;
}



/*++
Routine Description:
    
    Dump packet information for debug purpose
    
Arguments:
    
    pPkt      Pointer to the packet

Return Value:
 
    None
  

--*/  
VOID e100DumpPkt (
    IN PNDIS_PACKET Packet
    )
{
    PNDIS_BUFFER pPrevBuffer;
    PNDIS_BUFFER pBuffer;

    do
    {
        //
        // Get first buffer of the packet
        //
        NdisQueryPacket(Packet, NULL, NULL, &pBuffer, NULL);
        pPrevBuffer = NULL;

        //
        // Scan the buffer chain
        //
        while (pBuffer != NULL) 
        {
            PVOID pVa = NULL;
            ULONG BufLen = 0;

            BufLen = NdisBufferLength (pBuffer);

            pVa = NdisBufferVirtualAddress(pBuffer);

            pPrevBuffer = pBuffer;
            pBuffer = pBuffer->Next;
            
            if (pVa == NULL)
            {
                continue;
            }

            DBGPRINT(MP_WARN, ("Mdl %p, Va %p. Len %x\n", pPrevBuffer, pVa, BufLen));
            Dump( (CHAR* )pVa, BufLen, 0, 1 );                           
        }

    } while (FALSE);
}


/*++
Routine Description:
    
    Calculate the IP checksum
    
Arguments:
    
    Packet       Pointer to the packet
    IpHdrOffset  Offset of IP header from the beginning of the packet

Return Value:
 
    None
  

--*/  
VOID CalculateIpChecksum(
    IN  PUCHAR       StartVa,
    IN  ULONG        IpHdrOffset
    )
{
    
    IPHeader      *pIpHdr;
    ULONG          IpHdrLen;
    ULONG          TempXsum = 0;
    
   
    pIpHdr = (IPHeader *)(StartVa + IpHdrOffset);
    IpHdrLen = IP_HEADER_LENGTH(pIpHdr);

    XSUM(TempXsum, StartVa, IpHdrLen, IpHdrOffset);
    pIpHdr->iph_xsum = ~(USHORT)TempXsum;
}



/*++
Routine Description:
    
    Calculate the UDP checksum 
    
Arguments:
    
    Packet       Pointer to the packet
    IpHdrOffset  Offset of IP header from the beginning of the packet

Return Value:
 
    None
  

--*/  
VOID CalculateUdpChecksum(
    IN  PNDIS_PACKET    pPacket, 
    IN  ULONG           IpHdrOffset
    )
{
    UNREFERENCED_PARAMETER(pPacket);
    UNREFERENCED_PARAMETER(IpHdrOffset);
    
    DBGPRINT(MP_WARN, ("UdpChecksum is not handled\n"));
}




/*++
Routine Description:
    
    Calculate the TCP checksum 
    
Arguments:
    
    Packet       Pointer to the packet
    IpHdrOffset  Offset of IP header from the beginning of the packet

Return Value:
 
    None
  

--*/  
VOID CalculateTcpChecksum(
    IN  PVOID  StartVa,
    IN  ULONG  PacketLength,
    IN  ULONG  IpHdrOffset
    )
{
    ULONG        Offset;
    IPHeader     *pIpHdr;
    ULONG        IpHdrLength;
    TCPHeader    *pTcpHdr;
    USHORT       PseudoXsum;
    ULONG        TmpXsum;
 
    
    DBGPRINT(MP_TRACE, ("===> CalculateTcpChecksum\n"));
    
    //
    // Find IP header and get IP header length in byte
    // MDL won't split headers
    //
    Offset = IpHdrOffset;
    pIpHdr = (IPHeader *) ((PUCHAR)StartVa + Offset);
    IpHdrLength = IP_HEADER_LENGTH(pIpHdr);
  
    //
    // If that is not tcp protocol, we can not do anything.
    // So just return to the caller
    //
    if (((pIpHdr->iph_verlen & 0xF0) >> 4) != 4 && pIpHdr->iph_protocol != PROTOCOL_TCP)
    {
        return;
    }
   
    //
    // Locate the TCP header
    //
    Offset += IpHdrLength;
    pTcpHdr = (TCPHeader *) ((PUCHAR)StartVa + Offset);

    //
    // Calculate the checksum for the tcp header and payload
    //
    PseudoXsum = pTcpHdr->tcp_xsum;
 
    pTcpHdr->tcp_xsum = 0;
    TmpXsum = PseudoXsum;
    XSUM(TmpXsum, StartVa, PacketLength - Offset, Offset);
    
    //
    // Now we got the checksum, need to put the checksum back to MDL
    //
    pTcpHdr->tcp_xsum = (USHORT)(~TmpXsum);
    
    DBGPRINT(MP_TRACE, ("<=== CalculateTcpChecksum\n"));
}


/*++
Routine Description:
    
    Do the checksum offloading 
    
Arguments:
    
    Packet       Pointer to the packet
    IpHdrOffset  Offset of IP header from the beginning of the packet

Return Value:
 
    None
  

--*/  
VOID CalculateChecksum(
    IN  PVOID        StartVa,
    IN  ULONG        PacketLength,
    IN  PNDIS_PACKET Packet,
    IN  ULONG        IpHdrOffset
    )
{ 
    ULONG                             ChecksumPktInfo;
    PNDIS_TCP_IP_CHECKSUM_PACKET_INFO pChecksumPktInfo;
    
    //
    // Check for protocol
    //
    if (NDIS_PROTOCOL_ID_TCP_IP != NDIS_GET_PACKET_PROTOCOL_TYPE(Packet))
    {
        DBGPRINT(MP_TRACE, ("Packet's protocol is wrong.\n"));
        return;
    }

    //
    // Query per packet information 
    //
    ChecksumPktInfo = PtrToUlong(
                         NDIS_PER_PACKET_INFO_FROM_PACKET( Packet,
                                                           TcpIpChecksumPacketInfo));

  
    // DBGPRINT(MP_WARN, ("Checksum info: %lu\n", ChecksumPktInfo));
    
    pChecksumPktInfo = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO) & ChecksumPktInfo;
    
    //
    // Check per packet information
    //
    if (pChecksumPktInfo->Transmit.NdisPacketChecksumV4 == 0)
    {
        
        DBGPRINT(MP_TRACE, ("NdisPacketChecksumV4 is not set.\n"));
        return;
    }
    
    //
    // do tcp checksum
    //
    if (pChecksumPktInfo->Transmit.NdisPacketTcpChecksum)
    {
        CalculateTcpChecksum(StartVa, PacketLength, IpHdrOffset);
    }

    //
    // do udp checksum
    //
    if (pChecksumPktInfo->Transmit.NdisPacketUdpChecksum)
    {
        CalculateUdpChecksum(Packet, IpHdrOffset);
    }

    //
    // do ip checksum
    //
    if (pChecksumPktInfo->Transmit.NdisPacketIpChecksum)
    {
        CalculateIpChecksum(StartVa, IpHdrOffset);
    }
    
}

/*++

Routine Description:
    
    MiniportSendPackets handler
    
Arguments:

    MiniportAdapterContext  Pointer to our adapter
    PacketArray             Set of packets to send
    NumOfPackets         Self-explanatory

Return Value:

    None

--*/
VOID MPOffloadSendPackets(
    IN  NDIS_HANDLE    MiniportAdapterContext,
    IN  PPNDIS_PACKET  PacketArray,
    IN  UINT           NumOfPackets
    )
{
    PMP_ADAPTER  Adapter;
    NDIS_STATUS  Status;
    UINT         PacketCount;
    

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

    Adapter = (PMP_ADAPTER)MiniportAdapterContext;


    NdisAcquireSpinLock(&Adapter->SendLock);

    //
    // Is this adapter ready for sending?
    //
    if (MP_IS_NOT_READY(Adapter))
    {
        //
        // There is link
        //
        if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION))
        {
            for (PacketCount = 0; PacketCount < NumOfPackets; PacketCount++)
            {
                InsertTailQueue(&Adapter->SendWaitQueue, 
                                MP_GET_PACKET_MR( PacketArray[PacketCount] )
                               );
                
                Adapter->nWaitSend++;
                DBGPRINT(MP_WARN, ("MpOffloadSendPackets: link detection - queue packet "PTR_FORMAT"\n", PacketArray[PacketCount]));
            }
            NdisReleaseSpinLock(&Adapter->SendLock);

⌨️ 快捷键说明

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