1613 lines
55 KiB
C
1613 lines
55 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996-1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
send.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
routines for sending packets
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Charlie Wickham (charlwi) 07-May-1996
|
|||
|
Yoram Bernet (yoramb)
|
|||
|
Rajesh Sundaram (rajeshsu) 01-Aug-1998.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel Mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "psched.h"
|
|||
|
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
/* External */
|
|||
|
|
|||
|
/* Static */
|
|||
|
|
|||
|
/* Forwad */
|
|||
|
|
|||
|
#define SEND_PACKET_VIA_SCHEDULER(_pktcontext, _vc, _adapter, _ourpacket) \
|
|||
|
{ \
|
|||
|
PsAssert((_pktcontext)->Vc != 0); \
|
|||
|
(_vc)->Stats.PacketsScheduled++; \
|
|||
|
(_vc)->Stats.BytesScheduled.QuadPart += (_pktcontext)->Info.PacketLength; \
|
|||
|
if(!(*(_vc)->PsComponent->SubmitPacket)( \
|
|||
|
(_vc)->PsPipeContext, \
|
|||
|
(_vc)->PsFlowContext, \
|
|||
|
(_pktcontext)->Info.ClassMapContext, \
|
|||
|
&(_pktcontext)->Info)) { \
|
|||
|
\
|
|||
|
DropPacket((_adapter), (_vc), (_ourpacket), NDIS_STATUS_FAILURE); \
|
|||
|
} \
|
|||
|
return NDIS_STATUS_PENDING; \
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#define FILL_PKT_FOR_NIC(OPacket, UserC) \
|
|||
|
{ \
|
|||
|
NDIS_PACKET_8021Q_INFO VlanPriInfo; \
|
|||
|
\
|
|||
|
VlanPriInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET(OPacket, Ieee8021QInfo);\
|
|||
|
VlanPriInfo.TagHeader.UserPriority = (UserC); \
|
|||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(OPacket, Ieee8021QInfo) = VlanPriInfo.Value;\
|
|||
|
}
|
|||
|
|
|||
|
#define FILL_PKT_FOR_SCHED(Adapter, PktContext, Vc, OPacket, TOSNC, UserC, UserNC, \
|
|||
|
_IPHdr) \
|
|||
|
{ \
|
|||
|
ULONG _PacketLength; \
|
|||
|
FILL_PKT_FOR_NIC(OPacket, UserC); \
|
|||
|
NdisQueryPacket((OPacket), NULL, NULL, NULL, &(_PacketLength)); \
|
|||
|
(PktContext)->Info.PacketLength = (_PacketLength) - (Adapter)->HeaderSize; \
|
|||
|
(PktContext)->Info.ConformanceTime.QuadPart = 0; \
|
|||
|
(PktContext)->Info.ClassMapContext = 0; \
|
|||
|
(PktContext)->Info.UserPriorityNonConforming = (UserNC); \
|
|||
|
(PktContext)->Info.TOSNonConforming = (TOSNC); \
|
|||
|
(PktContext)->Info.IPHdr = (_IPHdr); \
|
|||
|
(PktContext)->Info.IPHeaderOffset = (Adapter)->IPHeaderOffset; \
|
|||
|
(PktContext)->Vc = (Vc); \
|
|||
|
}
|
|||
|
|
|||
|
#define SEND_PACKET_OVER_NIC(Adapter, Packet, UserC, Status) \
|
|||
|
{ \
|
|||
|
PPS_SEND_PACKET_CONTEXT _PktContext; \
|
|||
|
PNDIS_PACKET _OurPacket; \
|
|||
|
if((Status = PsDupPacketNoContext(Adapter, Packet, &_OurPacket, &_PktContext)) == NDIS_STATUS_SUCCESS) \
|
|||
|
{ \
|
|||
|
FILL_PKT_FOR_NIC(_OurPacket, UserC); \
|
|||
|
NdisSend(&Status, Adapter->LowerMpHandle, _OurPacket); \
|
|||
|
if(Status != NDIS_STATUS_PENDING) { \
|
|||
|
if(_PktContext) { \
|
|||
|
PsAssert((_PktContext)->Vc == 0); \
|
|||
|
NdisIMCopySendCompletePerPacketInfo(_PktContext->OriginalPacket, _OurPacket); \
|
|||
|
NdisFreePacket(_OurPacket); \
|
|||
|
} \
|
|||
|
} \
|
|||
|
} \
|
|||
|
return Status; \
|
|||
|
}
|
|||
|
|
|||
|
NDIS_STATUS
|
|||
|
PsAllocateAndCopyPacket(
|
|||
|
PADAPTER Adapter,
|
|||
|
PNDIS_PACKET Packet,
|
|||
|
PPNDIS_PACKET OurPacket,
|
|||
|
PPS_SEND_PACKET_CONTEXT *PktContext)
|
|||
|
{
|
|||
|
PNDIS_PACKET_OOB_DATA OurOOBData;
|
|||
|
PNDIS_PACKET_OOB_DATA XportOOBData;
|
|||
|
PMEDIA_SPECIFIC_INFORMATION OurMediaArea;
|
|||
|
PVOID MediaSpecificInfo = NULL;
|
|||
|
UINT MediaSpecificInfoSize = 0;
|
|||
|
NDIS_STATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// At this point, we know that there are no packet stacks remaining in the packet.
|
|||
|
// we proceed to allocate an NDIS packet using NdisAllocatePacket. Note that here
|
|||
|
// we do not have to allocate our per-packet area, since NdisAllocatePacket already
|
|||
|
// did this for us.
|
|||
|
//
|
|||
|
|
|||
|
if(!Adapter->SendPacketPool)
|
|||
|
{
|
|||
|
PS_LOCK(&Adapter->Lock);
|
|||
|
|
|||
|
if(!Adapter->SendPacketPool)
|
|||
|
{
|
|||
|
NDIS_HANDLE PoolHandle = (void *) NDIS_PACKET_POOL_TAG_FOR_PSCHED;
|
|||
|
|
|||
|
NdisAllocatePacketPoolEx(&Status,
|
|||
|
&PoolHandle,
|
|||
|
MIN_PACKET_POOL_SIZE,
|
|||
|
MAX_PACKET_POOL_SIZE,
|
|||
|
Adapter->PacketContextLength);
|
|||
|
|
|||
|
if(Status != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
Adapter->Stats.OutOfPackets ++;
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We successfully allocated a packet pool. We can now free the Fixed Size Block pool for the packet-stack API
|
|||
|
//
|
|||
|
Adapter->SendPacketPool = PoolHandle;
|
|||
|
}
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NdisAllocatePacket(&Status,
|
|||
|
OurPacket,
|
|||
|
Adapter->SendPacketPool);
|
|||
|
|
|||
|
|
|||
|
if(Status != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
//
|
|||
|
// mark as out of resources. Ndis will resubmit.
|
|||
|
//
|
|||
|
|
|||
|
Adapter->Stats.OutOfPackets ++;
|
|||
|
return(NDIS_STATUS_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
PsAssert((*OurPacket)->Private.Head == NULL);
|
|||
|
|
|||
|
if(Packet->Private.TotalLength){
|
|||
|
|
|||
|
PsAssert(Packet->Private.Head);
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
//
|
|||
|
// chain the buffers from the upper layer packet to the newly allocated packet.
|
|||
|
//
|
|||
|
|
|||
|
(*OurPacket)->Private.Head = Packet->Private.Head;
|
|||
|
(*OurPacket)->Private.Tail = Packet->Private.Tail;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Packet Flags from the Packet to OldPacket. Since we handle loopback in the
|
|||
|
// QueryInformation handlers, we don't set the NDIS_FLAGS_DONT_LOOPBACK
|
|||
|
//
|
|||
|
|
|||
|
NdisGetPacketFlags(*OurPacket) = NdisGetPacketFlags(Packet);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the OOB Offset from the original packet to the new packet.
|
|||
|
//
|
|||
|
XportOOBData = NDIS_OOB_DATA_FROM_PACKET(Packet);
|
|||
|
OurOOBData = NDIS_OOB_DATA_FROM_PACKET(*OurPacket);
|
|||
|
NdisMoveMemory(OurOOBData,
|
|||
|
XportOOBData,
|
|||
|
sizeof(NDIS_PACKET_OOB_DATA));
|
|||
|
|
|||
|
//
|
|||
|
// Copy the per packet info into the new packet
|
|||
|
//
|
|||
|
NdisIMCopySendPerPacketInfo(*OurPacket, Packet);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Media specific information
|
|||
|
//
|
|||
|
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
|
|||
|
&MediaSpecificInfo,
|
|||
|
&MediaSpecificInfoSize);
|
|||
|
if(MediaSpecificInfo || MediaSpecificInfoSize){
|
|||
|
|
|||
|
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(*OurPacket,
|
|||
|
MediaSpecificInfo,
|
|||
|
MediaSpecificInfoSize);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember the original packet so that we can complete it properly.
|
|||
|
//
|
|||
|
*PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(*OurPacket);
|
|||
|
(*PktContext)->OriginalPacket = Packet;
|
|||
|
(*PktContext)->Vc = 0;
|
|||
|
(*PktContext)->Info.NdisPacket = *OurPacket;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NDIS_STATUS
|
|||
|
PsDupPacketNoContext(
|
|||
|
PADAPTER Adapter,
|
|||
|
PNDIS_PACKET Packet,
|
|||
|
PPNDIS_PACKET OurPacket,
|
|||
|
PPS_SEND_PACKET_CONTEXT *PktContext)
|
|||
|
{
|
|||
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|||
|
BOOLEAN Remaining;
|
|||
|
PNDIS_PACKET_STACK PacketStack;
|
|||
|
|
|||
|
//
|
|||
|
// NDIS provides 2 ways for IMs to indicate packets. If the IM can allocate a packet stack, it should use it as
|
|||
|
// it is the optimal approach. In this case, we do not have to do any per-packet copying since we don't allocate
|
|||
|
// a new packet.
|
|||
|
//
|
|||
|
|
|||
|
PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
|
|||
|
|
|||
|
if(Remaining != 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// The packet stack has space only for 2 DWORDs. Since we are using more than 2, we need to allocate our own
|
|||
|
// memory for the per-packet block. Note that we *DONT* do this when we use the NdisAllocatePacket APIs, because
|
|||
|
// we initialized the packet pool to already include the space for the per-packet region.
|
|||
|
//
|
|||
|
|
|||
|
*OurPacket = Packet;
|
|||
|
*PktContext = 0;
|
|||
|
PacketStack->IMReserved[0] = 0;
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = PsAllocateAndCopyPacket(Adapter,
|
|||
|
Packet,
|
|||
|
OurPacket,
|
|||
|
PktContext);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NDIS_STATUS
|
|||
|
PsDupPacketContext(
|
|||
|
PADAPTER Adapter,
|
|||
|
PNDIS_PACKET Packet,
|
|||
|
PPNDIS_PACKET OurPacket,
|
|||
|
PPS_SEND_PACKET_CONTEXT *PktContext)
|
|||
|
{
|
|||
|
NDIS_STATUS Status;
|
|||
|
BOOLEAN Remaining;
|
|||
|
PNDIS_PACKET_STACK PacketStack;
|
|||
|
|
|||
|
//
|
|||
|
// NDIS provides 2 ways for IMs to indicate packets. If the IM can allocate a packet stack, it should use it as
|
|||
|
// it is the optimal approach. In this case, we do not have to do any per-packet copying since we don't allocate
|
|||
|
// a new packet.
|
|||
|
//
|
|||
|
|
|||
|
PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
|
|||
|
|
|||
|
if(Remaining != 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// The packet stack has space only for 2 DWORDs. Since we are using more than 2, we need to allocate our own
|
|||
|
// memory for the per-packet block. Note that we *DONT* do this when we use the NdisAllocatePacket APIs, because
|
|||
|
// we initialized the packet pool to already include the space for the per-packet region.
|
|||
|
//
|
|||
|
|
|||
|
*OurPacket = Packet;
|
|||
|
|
|||
|
*PktContext = (PPS_SEND_PACKET_CONTEXT) (ULONG_PTR)NdisAllocateFromBlockPool(Adapter->SendBlockPool);
|
|||
|
PacketStack->IMReserved[0] = (ULONG_PTR)*PktContext;
|
|||
|
|
|||
|
if(!*PktContext)
|
|||
|
{
|
|||
|
Adapter->Stats.OutOfPackets ++;
|
|||
|
return NDIS_STATUS_RESOURCES;
|
|||
|
}
|
|||
|
else {
|
|||
|
(*PktContext)->Info.NdisPacket = Packet;
|
|||
|
(*PktContext)->OriginalPacket = 0;
|
|||
|
return NDIS_STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = PsAllocateAndCopyPacket(Adapter,
|
|||
|
Packet,
|
|||
|
OurPacket,
|
|||
|
PktContext);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Tries to classify this packet based on the port numbers. If not found, will add it to one of the flows (in Round
|
|||
|
// Robin fashion) and returns a pointer to that Vc
|
|||
|
//
|
|||
|
PGPC_CLIENT_VC
|
|||
|
GetVcForPacket( PPS_WAN_LINK WanLink,
|
|||
|
USHORT SrcPort,
|
|||
|
USHORT DstPort)
|
|||
|
{
|
|||
|
PGPC_CLIENT_VC pVc, pVc1;
|
|||
|
int i, j;
|
|||
|
|
|||
|
|
|||
|
for( j = 0; j < BEVC_LIST_LEN; j++)
|
|||
|
{
|
|||
|
|
|||
|
pVc = &WanLink->BeVcList[j];
|
|||
|
|
|||
|
// Let's look at the 2 VCs we have now:
|
|||
|
for( i = 0; i < PORT_LIST_LEN; i++)
|
|||
|
{
|
|||
|
if( (pVc->SrcPort[i] == SrcPort) && (pVc->DstPort[i] == DstPort))
|
|||
|
return pVc;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Did not find in any of the VCs. Need to choose the Next VC for insertion and insert these valuse..
|
|||
|
pVc = &WanLink->BeVcList[WanLink->NextVc];
|
|||
|
WanLink->NextVc = ((WanLink->NextVc + 1) % BEVC_LIST_LEN);
|
|||
|
|
|||
|
pVc->SrcPort[pVc->NextSlot] = SrcPort;
|
|||
|
pVc->DstPort[pVc->NextSlot] = DstPort;
|
|||
|
pVc->NextSlot = ((pVc->NextSlot + 1)% PORT_LIST_LEN );
|
|||
|
return pVc;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// This routine returns the Src and Dst Port numbers
|
|||
|
BOOLEAN
|
|||
|
GetPortNos(
|
|||
|
IN PNDIS_PACKET Packet ,
|
|||
|
IN ULONG TransportHeaderOffset,
|
|||
|
IN OUT PUSHORT pSrcPort,
|
|||
|
IN OUT PUSHORT pDstPort
|
|||
|
)
|
|||
|
{
|
|||
|
PNDIS_BUFFER ArpBuf , IpBuf , TcpBuf, UdpBuf, DataBuf;
|
|||
|
ULONG ArpLen , IpLen , IpHdrLen , TcpLen , UdpLen, DataLen , TotalLen , TcpHeaderOffset;
|
|||
|
|
|||
|
VOID *ArpH;
|
|||
|
IPHeader UNALIGNED *IPH;
|
|||
|
TCPHeader UNALIGNED *TCPH;
|
|||
|
UDPHeader UNALIGNED *UDPH;
|
|||
|
|
|||
|
IPAddr Src, Dst;
|
|||
|
BOOLEAN bFragment;
|
|||
|
USHORT SrcPort , DstPort , IPID, FragOffset ,Size;
|
|||
|
PVOID GeneralVA , Data;
|
|||
|
ULONG i, Ret;
|
|||
|
|
|||
|
|
|||
|
IpBuf = NULL;
|
|||
|
|
|||
|
// Steps
|
|||
|
// Parse the IP Packet.
|
|||
|
// Look for the appropriate ports.
|
|||
|
// Look for the data portion and put in the Time & length there.
|
|||
|
|
|||
|
if(1)
|
|||
|
{
|
|||
|
PVOID pAddr;
|
|||
|
PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
|
|||
|
UINT Len;
|
|||
|
|
|||
|
NdisGetFirstBufferFromPacket( Packet,
|
|||
|
&ArpBuf,
|
|||
|
&ArpH,
|
|||
|
&ArpLen,
|
|||
|
&TotalLen
|
|||
|
);
|
|||
|
|
|||
|
pNdisBuf1 = Packet->Private.Head;
|
|||
|
NdisQueryBuffer(pNdisBuf1, &pAddr, &Len);
|
|||
|
|
|||
|
while(Len <= TransportHeaderOffset)
|
|||
|
{
|
|||
|
|
|||
|
TransportHeaderOffset -= Len;
|
|||
|
NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
|
|||
|
|
|||
|
NdisQueryBuffer(pNdisBuf2, &pAddr, &Len);
|
|||
|
pNdisBuf1 = pNdisBuf2;
|
|||
|
}
|
|||
|
|
|||
|
/* Buffer Descriptor corresponding to Ip Packet */
|
|||
|
IpBuf = pNdisBuf1;
|
|||
|
|
|||
|
/* Length of this Buffer (IP buffer) */
|
|||
|
IpLen = Len - TransportHeaderOffset;
|
|||
|
|
|||
|
/* Starting Virtual Address for this buffer */
|
|||
|
GeneralVA = pAddr;
|
|||
|
|
|||
|
/* Virtual Address of the IP Header */
|
|||
|
IPH = (IPHeader *)(((PUCHAR)pAddr) + TransportHeaderOffset);
|
|||
|
}
|
|||
|
|
|||
|
if(!IpBuf)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
IpHdrLen = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
|
|||
|
|
|||
|
FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
|
|||
|
FragOffset = net_short(FragOffset) * 8;
|
|||
|
|
|||
|
bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
|
|||
|
|
|||
|
// Don't want to deal with Fragmented packets right now..//
|
|||
|
if ( bFragment )
|
|||
|
return FALSE;
|
|||
|
|
|||
|
|
|||
|
switch (IPH->iph_protocol)
|
|||
|
{
|
|||
|
case IPPROTO_TCP :
|
|||
|
|
|||
|
if (IPH && ((USHORT)IpLen > IpHdrLen))
|
|||
|
{
|
|||
|
// We have more than the IP Header in this MDL //
|
|||
|
TCPH = (TCPHeader *) ((PUCHAR)IPH + IpHdrLen);
|
|||
|
TcpLen = IpLen - IpHdrLen;
|
|||
|
TcpBuf = IpBuf;
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// TCP Header is in the next MDL //
|
|||
|
NdisGetNextBuffer(IpBuf, &TcpBuf);
|
|||
|
|
|||
|
if(!TcpBuf)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
GeneralVA = NULL;
|
|||
|
NdisQueryBuffer(TcpBuf,
|
|||
|
&GeneralVA,
|
|||
|
&TcpLen
|
|||
|
);
|
|||
|
|
|||
|
TCPH = (TCPHeader *) GeneralVA;
|
|||
|
}
|
|||
|
|
|||
|
/* At this point, TcpBuf, TCPH and TcpLen contain the proper values */
|
|||
|
|
|||
|
// Get the port numbers out.
|
|||
|
SrcPort = net_short(TCPH->tcp_src);
|
|||
|
DstPort = net_short(TCPH->tcp_dest);
|
|||
|
|
|||
|
*pSrcPort = SrcPort;
|
|||
|
*pDstPort = DstPort;
|
|||
|
|
|||
|
// If the packet is here, it means: The link on which it is being sent is <= MAX_LINK_SPEED_FOR_DRR.
|
|||
|
// So, it is OK to adjust the Window size if we are on an ICS box.
|
|||
|
|
|||
|
if(gEnableWindowAdjustment)
|
|||
|
{
|
|||
|
USHORT _old, _new;
|
|||
|
ULONG _sum;
|
|||
|
|
|||
|
_old = (TCPH)->tcp_window;
|
|||
|
_new = 1460*6;
|
|||
|
|
|||
|
if( net_short( _old) < _new)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
_new = net_short( _new );
|
|||
|
(TCPH)->tcp_window = _new;
|
|||
|
|
|||
|
_sum = ((~(TCPH)->tcp_xsum) & 0xffff) + ((~_old) & 0xffff) + _new;
|
|||
|
_sum = (_sum & 0xffff) + (_sum >> 16);
|
|||
|
_sum += (_sum >> 16);
|
|||
|
(TCPH)->tcp_xsum = (ushort) ((~_sum) & 0xffff);
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
case IPPROTO_UDP:
|
|||
|
|
|||
|
if (IpLen > IpHdrLen)
|
|||
|
{
|
|||
|
// We have more than the IP Header in this MDL //
|
|||
|
UDPH = (UDPHeader *) ((PUCHAR)IPH + IpHdrLen);
|
|||
|
UdpLen = IpLen - IpHdrLen;
|
|||
|
UdpBuf = IpBuf;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// UDP Header is in the next MDL //
|
|||
|
NdisGetNextBuffer(IpBuf, &UdpBuf);
|
|||
|
|
|||
|
if(!UdpBuf)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
GeneralVA = NULL;
|
|||
|
NdisQueryBuffer(UdpBuf,
|
|||
|
&GeneralVA,
|
|||
|
&UdpLen
|
|||
|
);
|
|||
|
|
|||
|
UDPH = (UDPHeader *) GeneralVA;
|
|||
|
}
|
|||
|
|
|||
|
/* At this point, UdpBuf, UDPH and UdpLen contain the proper values */
|
|||
|
|
|||
|
SrcPort = net_short(UDPH->uh_src);
|
|||
|
DstPort = net_short(UDPH->uh_dest);
|
|||
|
|
|||
|
*pSrcPort = SrcPort;
|
|||
|
*pDstPort = DstPort;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
default:
|
|||
|
;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// This where we get called for each Send
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MpSend(
|
|||
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|||
|
IN PNDIS_PACKET TheirPacket,
|
|||
|
IN UINT Flags
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Received a xmit request from a legacy transport.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
See the DDK...
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
|
|||
|
NDIS_STATUS Status;
|
|||
|
PNDIS_PACKET OurPacket;
|
|||
|
PPS_SEND_PACKET_CONTEXT PktContext;
|
|||
|
PGPC_CLIENT_VC BeVc, Vc = NULL;
|
|||
|
PETH_HEADER pAddr;
|
|||
|
PNDIS_BUFFER pNdisBuf1;
|
|||
|
UINT Len;
|
|||
|
PUSHORT id;
|
|||
|
PPS_WAN_LINK WanLink;
|
|||
|
|
|||
|
PsStructAssert(Adapter);
|
|||
|
|
|||
|
//
|
|||
|
// If the device is shutting down, we cannot accept any more sends.
|
|||
|
//
|
|||
|
|
|||
|
if(IsDeviceStateOn(Adapter) == FALSE)
|
|||
|
{
|
|||
|
return NDIS_STATUS_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
if(Adapter->MediaType == NdisMediumWan)
|
|||
|
{
|
|||
|
if(Adapter->ProtocolType == ARP_ETYPE_IP)
|
|||
|
{
|
|||
|
//
|
|||
|
// We should not be getting non-ip packets in the NDISWAN-IP binding.
|
|||
|
//
|
|||
|
|
|||
|
PsAssert(NDIS_GET_PACKET_PROTOCOL_TYPE(TheirPacket) == NDIS_PROTOCOL_ID_TCP_IP);
|
|||
|
|
|||
|
pNdisBuf1 = TheirPacket->Private.Head;
|
|||
|
|
|||
|
NdisQueryBuffer(pNdisBuf1, &pAddr, &Len);
|
|||
|
|
|||
|
if(Len < sizeof(ETH_HEADER))
|
|||
|
{
|
|||
|
//
|
|||
|
// Packet is too small. we have to fail this bogus packet.
|
|||
|
//
|
|||
|
|
|||
|
return NDIS_STATUS_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get to the wanlink using the remote address from the packet.
|
|||
|
//
|
|||
|
|
|||
|
id = (PUSHORT) &pAddr->DestAddr[0];
|
|||
|
|
|||
|
PS_LOCK(&Adapter->Lock);
|
|||
|
|
|||
|
WanLink = (PPS_WAN_LINK)(g_WanLinkTable[*id]);
|
|||
|
|
|||
|
if(WanLink == 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// We received a packet for a wanlink that has already gone down.
|
|||
|
//
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
return NDIS_STATUS_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
if(WanLink->State != WanStateOpen)
|
|||
|
{
|
|||
|
//
|
|||
|
// We received a packet for a wanlink that has already gone down.
|
|||
|
//
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
return NDIS_STATUS_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// When we get a StatusIndication for a new WAN link, NDISWAN puts context in the remote address
|
|||
|
// When psched intercepts the LineUp, it overwrites NDISWAN's context with its own context. Psched
|
|||
|
// uses this context to get to the WanLink from the packet. (see above)
|
|||
|
//
|
|||
|
// But, when it passes the packet down to NDISWAN, it needs to plumb NDISWAN's context into the packet,
|
|||
|
// so that NDISWAN can see the context that it sent to us, as opposed to the context that we sent up to
|
|||
|
// wanarp.
|
|||
|
//
|
|||
|
|
|||
|
NdisMoveMemory(pAddr,
|
|||
|
&WanLink->SendHeader,
|
|||
|
FIELD_OFFSET(ETH_HEADER, Type));
|
|||
|
|
|||
|
//
|
|||
|
// We optimize psched to bypass the scheduling components when there are no flows. There are a set of
|
|||
|
// scheduling components per WanLink, so to be truly optimal, we need to check the FLowCount on a specific
|
|||
|
// WanLink.
|
|||
|
//
|
|||
|
|
|||
|
if( (WanLink->LinkSpeed > MAX_LINK_SPEED_FOR_DRR) && (!WanLink->CfInfosInstalled) )
|
|||
|
{
|
|||
|
// Bypass scheduling components, since there are no flows created on this
|
|||
|
// wanlink. Note that the UserPriority is never used over wanlinks, so we can set it to 0.
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
SEND_PACKET_OVER_NIC(Adapter,
|
|||
|
TheirPacket,
|
|||
|
0,
|
|||
|
Status);
|
|||
|
}
|
|||
|
//
|
|||
|
// Now, we are going to do either (1) DiffServ Or (2) IntServ. If the packet does not belong to either
|
|||
|
// of these categories, we will just hash it into one of the BeVcs we have and do simple DRR.
|
|||
|
//
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// There is at least one flow. we need to classify this packet. Since the flow is going
|
|||
|
// via the scheduling components, we have to allocate memory for the per-packet info
|
|||
|
// (if the packet-stack APIs are used) or a new packet descriptor, which will include the
|
|||
|
// per-packet info (if the old NDIS APIs are used) The packet that has been passed to us is
|
|||
|
// 'TheirPacket'. If the packet-stack APIs are used, then TheirPacket == OurPacket
|
|||
|
// if the non packet-stack APIs are used, then OurPacket == Newly Allocated Packet.
|
|||
|
//
|
|||
|
// In both cases, the code after this point will just use 'OurPacket' and the right thing will happen.
|
|||
|
//
|
|||
|
|
|||
|
if((Status = PsDupPacketContext(Adapter, TheirPacket, &OurPacket, &PktContext)) != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
// Case 1. DiffServMode //
|
|||
|
if(WanLink->AdapterMode == AdapterModeDiffservFlow)
|
|||
|
{
|
|||
|
//
|
|||
|
// If we are in Diffserv mode, we classify the packet based on the DSCP in the IP header.
|
|||
|
//
|
|||
|
|
|||
|
// Is there atleast ONE DiffServ Flow?
|
|||
|
if(Adapter->IPHeaderOffset && WanLink->pDiffServMapping)
|
|||
|
{
|
|||
|
IPHeader *pIpHdr;
|
|||
|
UCHAR tos;
|
|||
|
|
|||
|
pIpHdr = GetIpHeader(Adapter->IPHeaderOffset, OurPacket);
|
|||
|
tos = pIpHdr->iph_tos >> 2;
|
|||
|
|
|||
|
if((Vc = WanLink->pDiffServMapping[tos].Vc))
|
|||
|
{
|
|||
|
//
|
|||
|
// We found a VC for this packet.
|
|||
|
//
|
|||
|
|
|||
|
PsAssert(Vc->Adapter == Adapter);
|
|||
|
PsAssert(Vc->WanLink == WanLink);
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
|
|||
|
SET_TOS_XSUM(OurPacket,
|
|||
|
pIpHdr,
|
|||
|
(WanLink->pDiffServMapping[tos].ConformingOutboundDSField));
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
(WanLink->pDiffServMapping[tos].NonConformingOutboundDSField),
|
|||
|
WanLink->pDiffServMapping[tos].ConformingUserPriority,
|
|||
|
WanLink->pDiffServMapping[tos].NonConformingUserPriority,
|
|||
|
pIpHdr);
|
|||
|
|
|||
|
}
|
|||
|
// Could not classify packets to ANY of the DiffServ Flows. So, let's just do DRR across the BeVcs.
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// There are Diffserv flows installed, but not for this DSCP. Lets use the BEVCS.
|
|||
|
//
|
|||
|
|
|||
|
USHORT SrcPort, DstPort;
|
|||
|
|
|||
|
if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
|
|||
|
(GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
|
|||
|
Vc = GetVcForPacket( WanLink, SrcPort, DstPort);
|
|||
|
else
|
|||
|
Vc = &WanLink->BestEffortVc;
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
Vc->IPPrecedenceNonConforming,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Vc->UserPriorityNonConforming,
|
|||
|
pIpHdr);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
// No, there is not One, let's just do DRR across the BeVcs.
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// We are in Diffserv mode, but no Diffserv flows are created as yet. Let's use the BEVCS.
|
|||
|
//
|
|||
|
USHORT SrcPort, DstPort;
|
|||
|
|
|||
|
if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
|
|||
|
(GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
|
|||
|
Vc = GetVcForPacket( WanLink, SrcPort, DstPort);
|
|||
|
else
|
|||
|
Vc = &WanLink->BestEffortVc;
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
Vc->IPPrecedenceNonConforming,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Vc->UserPriorityNonConforming,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
}
|
|||
|
// Case 2. IntServMode
|
|||
|
else
|
|||
|
{
|
|||
|
USHORT SrcPort=0, DstPort=0;
|
|||
|
//
|
|||
|
// We are in RSVP mode, and we need to go to the GPC to classify the packet.
|
|||
|
// We already have a pointer to our WanLink. But, the wanlink could go away
|
|||
|
// when we release the lock and try to classify the packet. So, we take
|
|||
|
// a ref on the BestEffortVc for the WanLink.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if( (WanLink->LinkSpeed <= MAX_LINK_SPEED_FOR_DRR) &&
|
|||
|
(GetPortNos( TheirPacket, Adapter->IPHeaderOffset, &SrcPort, &DstPort)))
|
|||
|
BeVc = GetVcForPacket( WanLink, SrcPort, DstPort);
|
|||
|
else
|
|||
|
BeVc = &WanLink->BestEffortVc;
|
|||
|
|
|||
|
InterlockedIncrement(&BeVc->RefCount);
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
if( WanLink->CfInfosInstalled )
|
|||
|
Vc = GetVcByClassifyingPacket(Adapter, &WanLink->InterfaceID, OurPacket);
|
|||
|
|
|||
|
if(!Vc)
|
|||
|
{
|
|||
|
Vc = BeVc;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DerefClVc(BeVc);
|
|||
|
}
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
Vc->IPPrecedenceNonConforming,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Vc->UserPriorityNonConforming,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// There is at least one flow - We need to send this packet via the scheduling
|
|||
|
// components.
|
|||
|
//
|
|||
|
|
|||
|
if((Vc->ClVcState == CL_CALL_COMPLETE) ||
|
|||
|
(Vc->ClVcState == CL_MODIFY_PENDING))
|
|||
|
{
|
|||
|
SEND_PACKET_VIA_SCHEDULER(PktContext, Vc, Adapter, OurPacket);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Deref the ref that was added by the GPC.
|
|||
|
//
|
|||
|
|
|||
|
DerefClVc(Vc);
|
|||
|
|
|||
|
PsDbgSend(DBG_FAILURE, DBG_SEND, MP_SEND, NOT_READY, Adapter, Vc, TheirPacket, OurPacket);
|
|||
|
|
|||
|
if(PktContext->OriginalPacket)
|
|||
|
{
|
|||
|
NdisFreePacket(OurPacket);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NdisFreeToBlockPool((PUCHAR)PktContext);
|
|||
|
}
|
|||
|
|
|||
|
return(NDIS_STATUS_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// Forget about it. It's a Non-IP packet
|
|||
|
//
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// For non IP adapters, we just send over the NIC. Note that we don't create a best effort
|
|||
|
// Vc for such adapters. The only thing that we lose here is the ability to mark 802.1p on
|
|||
|
// such packets (we don't have a Vc, so we cannot supply a UserPriority value to the below
|
|||
|
// macro. But that is okay, since 802.1p is meaningful only in non LAN adapters.
|
|||
|
//
|
|||
|
|
|||
|
SEND_PACKET_OVER_NIC(Adapter,
|
|||
|
TheirPacket,
|
|||
|
0,
|
|||
|
Status);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// We have received a send at our non WAN binding.
|
|||
|
//
|
|||
|
|
|||
|
if(!Adapter->CfInfosInstalled &&
|
|||
|
Adapter->BestEffortLimit == UNSPECIFIED_RATE &&
|
|||
|
TsCount == 0 )
|
|||
|
{
|
|||
|
// There is no point in trying to classify if there are no flows installed
|
|||
|
|
|||
|
Vc = &Adapter->BestEffortVc;
|
|||
|
|
|||
|
PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
|
|||
|
|
|||
|
//
|
|||
|
// Bypass scheduling components.
|
|||
|
//
|
|||
|
SEND_PACKET_OVER_NIC(Adapter,
|
|||
|
TheirPacket,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Status);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// There is at least one flow, or we are in LimitedBestEffort mode. Let's try to classify the Vc.
|
|||
|
// In this case, the packet will have to go via the scheduling components.
|
|||
|
//
|
|||
|
//
|
|||
|
// Since the flow is going via the scheduling components, we have to allocate the per-packet info.
|
|||
|
// (if the new NDIS APIs are used) or a new packet descriptor, which will include the per-packet info
|
|||
|
// (if the old NDIS APIs are used)
|
|||
|
//
|
|||
|
|
|||
|
if(Adapter->AdapterMode == AdapterModeDiffservFlow)
|
|||
|
{
|
|||
|
//
|
|||
|
// We are in the diffserv mode. We don't have to use the GPC to classify packets.
|
|||
|
// For all IP packets, classify on the TOS byte.
|
|||
|
//
|
|||
|
|
|||
|
PS_LOCK(&Adapter->Lock);
|
|||
|
|
|||
|
if(NDIS_GET_PACKET_PROTOCOL_TYPE(TheirPacket) == NDIS_PROTOCOL_ID_TCP_IP &&
|
|||
|
Adapter->IPHeaderOffset &&
|
|||
|
Adapter->pDiffServMapping)
|
|||
|
{
|
|||
|
UCHAR tos;
|
|||
|
IPHeader *pIpHdr = 0;
|
|||
|
|
|||
|
pIpHdr = GetIpHeader(Adapter->IPHeaderOffset, TheirPacket);
|
|||
|
tos = pIpHdr->iph_tos >> 2;
|
|||
|
|
|||
|
if((Vc = Adapter->pDiffServMapping[tos].Vc))
|
|||
|
{
|
|||
|
PsAssert(Vc->Adapter == Adapter);
|
|||
|
|
|||
|
|
|||
|
if((Status = PsDupPacketContext(Adapter,
|
|||
|
TheirPacket,
|
|||
|
&OurPacket,
|
|||
|
&PktContext)) != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
|
|||
|
SET_TOS_XSUM(OurPacket,
|
|||
|
pIpHdr,
|
|||
|
(Adapter->pDiffServMapping[tos].ConformingOutboundDSField));
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
(Adapter->pDiffServMapping[tos].NonConformingOutboundDSField),
|
|||
|
Adapter->pDiffServMapping[tos].ConformingUserPriority,
|
|||
|
Adapter->pDiffServMapping[tos].NonConformingUserPriority,
|
|||
|
pIpHdr);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if( ( Adapter->MaxOutstandingSends == 0xffffffff) &&
|
|||
|
( TsCount == 0))
|
|||
|
{
|
|||
|
Vc = &Adapter->BestEffortVc;
|
|||
|
|
|||
|
PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
|
|||
|
|
|||
|
//
|
|||
|
// Bypass scheduling components.
|
|||
|
//
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
SEND_PACKET_OVER_NIC(Adapter,
|
|||
|
TheirPacket,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Status);
|
|||
|
}
|
|||
|
|
|||
|
Vc = &Adapter->BestEffortVc;
|
|||
|
|
|||
|
if((Status = PsDupPacketContext(Adapter,
|
|||
|
TheirPacket,
|
|||
|
&OurPacket,
|
|||
|
&PktContext)) != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
Vc->IPPrecedenceNonConforming,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Vc->UserPriorityNonConforming,
|
|||
|
NULL);
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// We are in Diffserv mode, but there are no DiffServ Vcs, or it's not an IP
|
|||
|
// packet. Send over the Adapter's BE Vc.
|
|||
|
//
|
|||
|
|
|||
|
Vc = &Adapter->BestEffortVc;
|
|||
|
|
|||
|
if((Status = PsDupPacketContext( Adapter,
|
|||
|
TheirPacket,
|
|||
|
&OurPacket,
|
|||
|
&PktContext)) != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
Vc->IPPrecedenceNonConforming,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Vc->UserPriorityNonConforming,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
PS_UNLOCK(&Adapter->Lock);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// We are in RSVP mode. Let's classify with the GPC.
|
|||
|
|
|||
|
Vc = GetVcByClassifyingPacket(Adapter, &Adapter->InterfaceID, TheirPacket);
|
|||
|
|
|||
|
if( !Vc)
|
|||
|
{
|
|||
|
if( (Adapter->MaxOutstandingSends == 0xffffffff) &&
|
|||
|
(TsCount == 0))
|
|||
|
{
|
|||
|
Vc = &Adapter->BestEffortVc;
|
|||
|
|
|||
|
PsAssert(Vc->ClVcState == CL_CALL_COMPLETE);
|
|||
|
|
|||
|
//
|
|||
|
// Bypass scheduling components.
|
|||
|
//
|
|||
|
SEND_PACKET_OVER_NIC(Adapter,
|
|||
|
TheirPacket,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Status);
|
|||
|
}
|
|||
|
|
|||
|
// We will be doing DRR on this adapter; so send pkt on BeVc
|
|||
|
Vc = &Adapter->BestEffortVc;
|
|||
|
|
|||
|
InterlockedIncrement(&Vc->RefCount);
|
|||
|
}
|
|||
|
|
|||
|
if((Status = PsDupPacketContext(Adapter, TheirPacket, &OurPacket, &PktContext)) != NDIS_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
FILL_PKT_FOR_SCHED(Adapter,
|
|||
|
PktContext,
|
|||
|
Vc,
|
|||
|
OurPacket,
|
|||
|
Vc->IPPrecedenceNonConforming,
|
|||
|
Vc->UserPriorityConforming,
|
|||
|
Vc->UserPriorityNonConforming,
|
|||
|
NULL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if((Vc->ClVcState == CL_CALL_COMPLETE) ||
|
|||
|
(Vc->ClVcState == CL_MODIFY_PENDING) ||
|
|||
|
(Vc->ClVcState == CL_INTERNAL_CALL_COMPLETE))
|
|||
|
{
|
|||
|
SEND_PACKET_VIA_SCHEDULER(PktContext, Vc, Adapter, OurPacket);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Deref the ref that was added by the GPC.
|
|||
|
//
|
|||
|
|
|||
|
DerefClVc(Vc);
|
|||
|
|
|||
|
PsDbgSend(DBG_FAILURE, DBG_SEND, MP_SEND, NOT_READY, Adapter, Vc, TheirPacket, OurPacket);
|
|||
|
|
|||
|
if(PktContext->OriginalPacket)
|
|||
|
{
|
|||
|
NdisFreePacket(OurPacket);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NdisFreeToBlockPool((PUCHAR)PktContext);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return(NDIS_STATUS_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ClSendComplete(
|
|||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|||
|
IN PNDIS_PACKET Packet,
|
|||
|
IN NDIS_STATUS Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Completion routine for NdisSendPackets.
|
|||
|
Does most of the work for cleaning up after a send.
|
|||
|
|
|||
|
If necessary, call the PSA's send packet complete function
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
See the DDK...
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PGPC_CLIENT_VC Vc;
|
|||
|
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
|
|||
|
PPS_SEND_PACKET_CONTEXT PktContext;
|
|||
|
PNDIS_PACKET XportPacket;
|
|||
|
HANDLE PoolHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if the packet we are completing is the one we allocated. If so, get
|
|||
|
// the original packet from the reserved area and free the allocated packet. If this
|
|||
|
// is the packet that was sent down to us then just complete the packet.
|
|||
|
//
|
|||
|
|
|||
|
PoolHandle = NdisGetPoolFromPacket(Packet);
|
|||
|
|
|||
|
if(PoolHandle != Adapter->SendPacketPool)
|
|||
|
{
|
|||
|
PNDIS_PACKET_STACK PacketStack;
|
|||
|
BOOLEAN Remaining;
|
|||
|
|
|||
|
PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
|
|||
|
|
|||
|
PsAssert(Remaining != 0);
|
|||
|
|
|||
|
PktContext = (PPS_SEND_PACKET_CONTEXT) PacketStack->IMReserved[0];
|
|||
|
|
|||
|
if(PktContext != 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// This packet went via the scheduling components.
|
|||
|
//
|
|||
|
|
|||
|
PsAssert(PktContext->Vc);
|
|||
|
Vc = PktContext->Vc;
|
|||
|
PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, Vc, Packet, 0);
|
|||
|
PsAssert(Vc->Adapter == Adapter);
|
|||
|
if(Vc->SendComplete)
|
|||
|
(*Vc->SendComplete)(Vc->SendCompletePipeContext, Packet);
|
|||
|
DerefClVc(Vc);
|
|||
|
NdisFreeToBlockPool((PUCHAR)PktContext);
|
|||
|
}
|
|||
|
|
|||
|
NdisMSendComplete(Adapter->PsNdisHandle,
|
|||
|
Packet,
|
|||
|
Status);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// get the pointer to the upper layer's packet. Reinit the packet struct and
|
|||
|
// push it back on the adapter's packet SList. Remove the reference incurred
|
|||
|
// when the packet was handled by MpSend
|
|||
|
//
|
|||
|
|
|||
|
PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(Packet);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Call the scheduler if necessary
|
|||
|
//
|
|||
|
|
|||
|
if(PktContext->Vc)
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Some packets never went through the scheduler.
|
|||
|
//
|
|||
|
Vc = PktContext->Vc;
|
|||
|
|
|||
|
PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, Vc, Packet, 0);
|
|||
|
|
|||
|
PsAssert(Vc->Adapter == Adapter);
|
|||
|
|
|||
|
if(Vc->SendComplete)
|
|||
|
{
|
|||
|
(*Vc->SendComplete)(Vc->SendCompletePipeContext, Packet);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We have taken a ref on the VCs when we sent the packets
|
|||
|
// through the scheduling components. Now is the time to
|
|||
|
// Deref them
|
|||
|
//
|
|||
|
|
|||
|
DerefClVc(Vc);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PsDbgSend(DBG_INFO, DBG_SEND, CL_SEND_COMPLETE, ENTER, Adapter, 0, Packet, 0);
|
|||
|
}
|
|||
|
|
|||
|
XportPacket = PktContext->OriginalPacket;
|
|||
|
|
|||
|
NdisIMCopySendCompletePerPacketInfo(XportPacket, Packet);
|
|||
|
|
|||
|
NdisFreePacket(Packet);
|
|||
|
|
|||
|
NdisMSendComplete(Adapter->PsNdisHandle,
|
|||
|
XportPacket,
|
|||
|
Status);
|
|||
|
}
|
|||
|
|
|||
|
} // ClSendComplete
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DropPacket(
|
|||
|
IN HANDLE PipeContext,
|
|||
|
IN HANDLE FlowContext,
|
|||
|
IN PNDIS_PACKET Packet,
|
|||
|
IN NDIS_STATUS Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Drop a packet after it was queued by the scheduler.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PipeContext - Pipe context (adapter)
|
|||
|
FlowContext - Flow context (adapter VC)
|
|||
|
Packet - Packet to drop
|
|||
|
Status - Return code to return to NDIS
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)FlowContext;
|
|||
|
PADAPTER Adapter = (PADAPTER)PipeContext;
|
|||
|
PPS_SEND_PACKET_CONTEXT PktContext;
|
|||
|
PNDIS_PACKET XportPacket;
|
|||
|
HANDLE PoolHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if the packet we are completing is the one we allocated. If so, get
|
|||
|
// the original packet from the reserved area and free the allocated packet. If this
|
|||
|
// is the packet that was sent down to us then just complete the packet.
|
|||
|
//
|
|||
|
|
|||
|
PoolHandle = NdisGetPoolFromPacket(Packet);
|
|||
|
|
|||
|
if(PoolHandle != Adapter->SendPacketPool)
|
|||
|
{
|
|||
|
PNDIS_PACKET_STACK PacketStack;
|
|||
|
BOOLEAN Remaining;
|
|||
|
|
|||
|
PacketStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
|
|||
|
|
|||
|
PsAssert(Remaining != 0);
|
|||
|
|
|||
|
PktContext = (PPS_SEND_PACKET_CONTEXT) PacketStack->IMReserved[0];
|
|||
|
|
|||
|
PsAssert(PktContext != 0);
|
|||
|
PsAssert(Vc == PktContext->Vc);
|
|||
|
PsAssert(Adapter == Vc->Adapter);
|
|||
|
NdisFreeToBlockPool((PUCHAR)PktContext);
|
|||
|
|
|||
|
NdisMSendComplete(Adapter->PsNdisHandle,
|
|||
|
Packet,
|
|||
|
Status);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PktContext = PS_SEND_PACKET_CONTEXT_FROM_PACKET(Packet);
|
|||
|
|
|||
|
PsAssert(PktContext != 0);
|
|||
|
PsAssert(Vc == PktContext->Vc);
|
|||
|
PsAssert(Adapter == Vc->Adapter);
|
|||
|
|
|||
|
XportPacket = PktContext->OriginalPacket;
|
|||
|
|
|||
|
NdisFreePacket(Packet);
|
|||
|
|
|||
|
NdisMSendComplete(Adapter->PsNdisHandle,
|
|||
|
XportPacket,
|
|||
|
Status);
|
|||
|
}
|
|||
|
|
|||
|
Vc->Stats.DroppedPackets ++;
|
|||
|
|
|||
|
PsDbgSend(DBG_INFO, DBG_SEND, DROP_PACKET, ENTER, Adapter, Vc, Packet, 0);
|
|||
|
|
|||
|
DerefClVc(Vc);
|
|||
|
|
|||
|
} // DropPacket
|
|||
|
|
|||
|
|
|||
|
char*
|
|||
|
ReturnByteAtOffset( PNDIS_PACKET pNdisPacket, ULONG Offset)
|
|||
|
{
|
|||
|
PVOID VA;
|
|||
|
PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
|
|||
|
UINT Len;
|
|||
|
|
|||
|
pNdisBuf1 = pNdisPacket->Private.Head;
|
|||
|
NdisQueryBuffer(pNdisBuf1, &VA, &Len);
|
|||
|
|
|||
|
while(Len <= Offset)
|
|||
|
{
|
|||
|
Offset -= Len;
|
|||
|
NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
|
|||
|
NdisQueryBuffer(pNdisBuf2, &VA, &Len);
|
|||
|
pNdisBuf1 = pNdisBuf2;
|
|||
|
}
|
|||
|
|
|||
|
return (char*)(((char*)VA) + Offset);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PGPC_CLIENT_VC FASTCALL
|
|||
|
GetVcByClassifyingPacket(
|
|||
|
PADAPTER Adapter,
|
|||
|
PTC_INTERFACE_ID pInterfaceID,
|
|||
|
PNDIS_PACKET OurPacket
|
|||
|
)
|
|||
|
/*+++
|
|||
|
|
|||
|
|
|||
|
---*/
|
|||
|
{
|
|||
|
CLASSIFICATION_HANDLE ClassificationHandle;
|
|||
|
PGPC_CLIENT_VC Vc = NULL;
|
|||
|
#if CBQ
|
|||
|
PCLASS_MAP_CONTEXT_BLK pClBlk = NULL;
|
|||
|
#endif
|
|||
|
NDIS_STATUS Status;
|
|||
|
ULONG ProtocolType;
|
|||
|
|
|||
|
//
|
|||
|
// We are in RSVP mode - Use the GPC to classify the packet. If the GPC wants to return a Vc, it will
|
|||
|
// return with a ref.
|
|||
|
//
|
|||
|
|
|||
|
ClassificationHandle = (CLASSIFICATION_HANDLE)
|
|||
|
PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo));
|
|||
|
|
|||
|
if (ClassificationHandle)
|
|||
|
{
|
|||
|
|
|||
|
PsAssert(GpcEntries.GpcGetCfInfoClientContextHandler);
|
|||
|
|
|||
|
Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(GpcQosClientHandle,
|
|||
|
ClassificationHandle,
|
|||
|
FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
|
|||
|
|
|||
|
#if CBQ
|
|||
|
pClBlk = NULL;
|
|||
|
Status = GpcEntries.GpcGetCfInfoClientContextHandler(GpcClassMapClientHandle,
|
|||
|
ClassificationHandle,
|
|||
|
&pClBlk);
|
|||
|
if(pClBlk)
|
|||
|
{
|
|||
|
PktContext->Info.ClassMapContext = pClBlk->ComponentContext;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// If we got a Vc that was not destined for this adapter, we have to reject it.
|
|||
|
//
|
|||
|
|
|||
|
if(Vc)
|
|||
|
{
|
|||
|
if(Vc->Adapter != Adapter)
|
|||
|
{
|
|||
|
DerefClVc(Vc);
|
|||
|
}
|
|||
|
else
|
|||
|
return Vc;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Let's classify this packet since we did not get a Classification ID or a proper Vc.
|
|||
|
//
|
|||
|
|
|||
|
PsAssert(GpcEntries.GpcClassifyPacketHandler);
|
|||
|
|
|||
|
switch(NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket))
|
|||
|
{
|
|||
|
case NDIS_PROTOCOL_ID_TCP_IP:
|
|||
|
ProtocolType = GPC_PROTOCOL_TEMPLATE_IP;
|
|||
|
break;
|
|||
|
case NDIS_PROTOCOL_ID_IPX:
|
|||
|
ProtocolType = GPC_PROTOCOL_TEMPLATE_IPX;
|
|||
|
break;
|
|||
|
default:
|
|||
|
ProtocolType = GPC_PROTOCOL_TEMPLATE_NOT_SPECIFIED;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the adapter type is 802.5 (Token Ring), then the MAC header can be of variable size.
|
|||
|
// The format of the MAC header is as follows:
|
|||
|
// +---------------------+-------------+----------+-----------
|
|||
|
// | 2 + 6 (DA) + 6 (SA) | Optional RI | 8 (SNAP) | IP
|
|||
|
// +---------------------+-------------+----------+-----------
|
|||
|
// Optional RI is present if and only if RI bit as part of SA is set.
|
|||
|
// When RI is present, its length is give by the lower 5 bits of the 15th byte.
|
|||
|
|
|||
|
// 1. Get the VA for the 9th and the 15th bytes.
|
|||
|
// 2. If RI if not present, Offset = 14 + 6.
|
|||
|
// 3. If present, Offset = 14 + 6 + RI-Size.
|
|||
|
|
|||
|
if(Adapter->MediaType == NdisMedium802_5)
|
|||
|
{
|
|||
|
PNDIS_BUFFER pTempNdisBuffer;
|
|||
|
PUCHAR pHeaderBuffer;
|
|||
|
ULONG BufferLength;
|
|||
|
ULONG TotalLength;
|
|||
|
ULONG IpOffset;
|
|||
|
|
|||
|
NdisGetFirstBufferFromPacket( OurPacket,
|
|||
|
&pTempNdisBuffer,
|
|||
|
&pHeaderBuffer,
|
|||
|
&BufferLength,
|
|||
|
&TotalLength);
|
|||
|
|
|||
|
ASSERT( BufferLength >= 15);
|
|||
|
|
|||
|
if( (*(ReturnByteAtOffset(OurPacket, 8)) & 0x80) == 0)
|
|||
|
IpOffset = 14 + 8;
|
|||
|
else
|
|||
|
IpOffset = 14 + 8 + (*(ReturnByteAtOffset(OurPacket, 14)) & 0x1f);
|
|||
|
|
|||
|
Status = GpcEntries.GpcClassifyPacketHandler(
|
|||
|
GpcQosClientHandle,
|
|||
|
ProtocolType,
|
|||
|
OurPacket,
|
|||
|
IpOffset,
|
|||
|
pInterfaceID,
|
|||
|
(PGPC_CLIENT_HANDLE)&Vc,
|
|||
|
&ClassificationHandle);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
|
|||
|
Status = GpcEntries.GpcClassifyPacketHandler(
|
|||
|
GpcQosClientHandle,
|
|||
|
ProtocolType,
|
|||
|
OurPacket,
|
|||
|
// This is basically to cover up a bug in wandrv.sys, which gives bogus frame header sizes. We look at the
|
|||
|
// Ip Header offset supplied by the protocol above for IP packets only, as we are saving only those for the
|
|||
|
// time being.
|
|||
|
((NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket) == NDIS_PROTOCOL_ID_TCP_IP) && (Adapter->IPHeaderOffset))
|
|||
|
? (Adapter->IPHeaderOffset)
|
|||
|
: Adapter->HeaderSize,
|
|||
|
pInterfaceID,
|
|||
|
(PGPC_CLIENT_HANDLE)&Vc,
|
|||
|
&ClassificationHandle);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if(Status == GPC_STATUS_SUCCESS)
|
|||
|
{
|
|||
|
//
|
|||
|
// If we have succeeded, we must get a Classification Handle
|
|||
|
//
|
|||
|
PsAssert(ClassificationHandle != 0);
|
|||
|
|
|||
|
//
|
|||
|
// The Classification succeeded. If we found a ClassificationHandle
|
|||
|
// then we must write it in the packet so that anyone below us can use
|
|||
|
// it. The very fact that we are here indicates that we did not start
|
|||
|
// with a Classification handle or we got a bad one. So, we need not
|
|||
|
// worry about over writing the classification handle in the packet.
|
|||
|
//
|
|||
|
|
|||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo) = UlongToPtr(ClassificationHandle);
|
|||
|
|
|||
|
Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(GpcQosClientHandle,
|
|||
|
ClassificationHandle,
|
|||
|
FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
|
|||
|
|
|||
|
#if CBQ
|
|||
|
//
|
|||
|
// Get the CBQ class map context & store it in the
|
|||
|
// packet. No point doing this if the first classification
|
|||
|
// failed.
|
|||
|
//
|
|||
|
|
|||
|
pClBlk = NULL;
|
|||
|
Status = GpcEntries.GpcGetCfInfoClientContextHandler(GpcClassMapClientHandle,
|
|||
|
ClassificationHandle,
|
|||
|
&pClBlk);
|
|||
|
|
|||
|
if(pClBlk)
|
|||
|
{
|
|||
|
PktContext->Info.ClassMapContext = pClBlk->ComponentContext;
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
if(Vc && Vc->Adapter != Adapter)
|
|||
|
{
|
|||
|
//
|
|||
|
// We have used the GPC APIs that return a Vc with a ref. We have to deref here, because we got a wrong Vc
|
|||
|
// for this adapter.
|
|||
|
//
|
|||
|
|
|||
|
DerefClVc(Vc);
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
return Vc;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ClCoSendComplete(
|
|||
|
IN NDIS_STATUS Status,
|
|||
|
IN NDIS_HANDLE ProtocolVcContext,
|
|||
|
IN PNDIS_PACKET Packet
|
|||
|
)
|
|||
|
{
|
|||
|
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC) ProtocolVcContext;
|
|||
|
|
|||
|
ClSendComplete(Vc->Adapter,
|
|||
|
Packet,
|
|||
|
Status);
|
|||
|
} // ClCoSendComplete
|
|||
|
|
|||
|
/* end send.c */
|