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