You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1383 lines
45 KiB
1383 lines
45 KiB
/*++
|
|
|
|
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 ((USHORT)IpLen > IpHdrLen)
|
|
{
|
|
// We have more than the IP Header in this MDL //
|
|
TCPH = (TCPHeader *) ((PUCHAR)IPH + IpHdrLen);
|
|
TcpLen = IpLen - IpHdrLen;
|
|
TcpBuf = IpBuf;
|
|
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* 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.
|
|
|
|
// Note that, we only do this on WAN adapters, which do not have the checksum offload
|
|
// capability. So, we are fine with changing the checksum.
|
|
|
|
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
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
if (1)
|
|
{
|
|
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) ||
|
|
(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);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// 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 )
|
|
{
|
|
// 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(1)
|
|
{
|
|
// We are in RSVP mode. Let's classify with the GPC.
|
|
|
|
Vc = GetVcByClassifyingPacket(Adapter, &Adapter->InterfaceID, TheirPacket);
|
|
|
|
if( !Vc)
|
|
{
|
|
if( Adapter->MaxOutstandingSends == 0xffffffff)
|
|
{
|
|
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;
|
|
NDIS_STATUS Status;
|
|
ULONG ProtocolType;
|
|
|
|
//
|
|
// Let's act based on the ClassificationType we read from the registry key.
|
|
// This is specific to debug version only.
|
|
// case 0: (default): Use preclassification information, classify otherwise
|
|
// case 1: Use prelcassification information ONLY
|
|
// case 2: Use classification information ONLY
|
|
//
|
|
|
|
ClassificationHandle = (CLASSIFICATION_HANDLE)
|
|
PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(OurPacket, ClassificationHandlePacketInfo));
|
|
|
|
#if DBG
|
|
if (ClassificationType == 2) {
|
|
ClassificationHandle = 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
if (ClassificationHandle)
|
|
{
|
|
|
|
PsAssert(GpcEntries.GpcGetCfInfoClientContextHandler);
|
|
|
|
Vc = GpcEntries.GpcGetCfInfoClientContextWithRefHandler(GpcQosClientHandle,
|
|
ClassificationHandle,
|
|
FIELD_OFFSET(GPC_CLIENT_VC, RefCount));
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (ClassificationType == 1) {
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// 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
|
|
{
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
PUCHAR pHeaderBuffer;
|
|
ULONG BufferLength;
|
|
ULONG TotalLength;
|
|
ULONG IpOffset;
|
|
PVOID VA;
|
|
PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
|
|
UINT Len;
|
|
ENetHeader UNALIGNED * EHdr;
|
|
|
|
pNdisBuf1 = OurPacket->Private.Head;
|
|
NdisQueryBuffer(pNdisBuf1, &VA, &Len);
|
|
|
|
EHdr = (ENetHeader UNALIGNED *)VA;
|
|
|
|
if (EHdr == NULL)
|
|
return NULL;
|
|
|
|
// We don't want to do any fancy parsing other than this. If the frame
|
|
// is not of standard ethernet type, bail out.
|
|
if ((Adapter->MediaType == NdisMedium802_3) && (net_short(EHdr->eh_type) >= MIN_ETYPE))
|
|
{
|
|
ULONG FrameOffset;
|
|
|
|
// The conditional 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.
|
|
|
|
if ((NDIS_GET_PACKET_PROTOCOL_TYPE(OurPacket) == NDIS_PROTOCOL_ID_TCP_IP) &&
|
|
(Adapter->IPHeaderOffset)) {
|
|
FrameOffset = Adapter->IPHeaderOffset;
|
|
} else {
|
|
FrameOffset = Adapter->HeaderSize;
|
|
}
|
|
|
|
Status = GpcEntries.GpcClassifyPacketHandler(
|
|
GpcQosClientHandle,
|
|
ProtocolType,
|
|
OurPacket,
|
|
FrameOffset,
|
|
pInterfaceID,
|
|
(PGPC_CLIENT_HANDLE)&Vc,
|
|
&ClassificationHandle);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
|
|
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(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 */
|