📄 offload.c
字号:
/*++
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 + -