windows-nt/Source/XPSP1/NT/net/qos/psched/sys/timestmp.c
2020-09-26 16:20:57 +08:00

1301 lines
36 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
TimeStmp.c
Abstract:
TimeStamp module
Author:
Shreem, Sanjayka
Environment:
Kernel Mode
Revision History:
--*/
#include "psched.h"
#pragma hdrstop
// The pipe information
typedef struct _TS_PIPE
{
// ContextInfo - Generic context info
PS_PIPE_CONTEXT ContextInfo;
} TS_PIPE, *PTS_PIPE;
// The flow information
typedef struct _TS_FLOW
{
// ContextInfo - Generic context info
PS_FLOW_CONTEXT ContextInfo;
} TS_FLOW, *PTS_FLOW;
/* Global variables */
LIST_ENTRY TsList;
NDIS_SPIN_LOCK TsSpinLock;
ULONG TsCount;
/* Static */
/* Forward */
NDIS_STATUS
TimeStmpInitializePipe (
IN HANDLE PsPipeContext,
IN PPS_PIPE_PARAMETERS PipeParameters,
IN PPS_PIPE_CONTEXT ComponentPipeContext,
IN PPS_PROCS PsProcs,
IN PPS_UPCALLS Upcalls
);
NDIS_STATUS
TimeStmpModifyPipe (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_PIPE_PARAMETERS PipeParameters
);
VOID
TimeStmpDeletePipe (
IN PPS_PIPE_CONTEXT PipeContext
);
NDIS_STATUS
TimeStmpCreateFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN HANDLE PsFlowContext,
IN PCO_CALL_PARAMETERS CallParameters,
IN PPS_FLOW_CONTEXT ComponentFlowContext
);
NDIS_STATUS
TimeStmpModifyFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PCO_CALL_PARAMETERS CallParameters
);
VOID
TimeStmpDeleteFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext
);
VOID
TimeStmpEmptyFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext
);
VOID
TimeStmpSetInformation (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN NDIS_OID Oid,
IN ULONG Len,
IN void *Data);
VOID
TimeStmpQueryInformation (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN NDIS_OID Oid,
IN ULONG Len,
IN PVOID Data,
IN OUT PULONG BytesWritten,
IN OUT PULONG BytesNeeded,
IN OUT PNDIS_STATUS Status);
NDIS_STATUS
TimeStmpCreateClassMap (
IN PPS_PIPE_CONTEXT PipeContext,
IN HANDLE PsClassMapContext,
IN PTC_CLASS_MAP_FLOW ClassMap,
IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
);
NDIS_STATUS
TimeStmpDeleteClassMap (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
);
BOOLEAN
TimeStmpSubmitPacket (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
IN PPACKET_INFO_BLOCK Packet
);
BOOLEAN
TimeStmpReceivePacket (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
IN PNDIS_PACKET Packet,
IN NDIS_MEDIUM Medium
);
BOOLEAN
TimeStmpReceiveIndication(
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize,
IN UINT TransportHeaderOffset
);
/* End Forward */
VOID
InitializeTimeStmp( PPSI_INFO Info )
{
Info->PipeContextLength = ((sizeof(TS_PIPE)+7) & ~7);
Info->FlowContextLength = ((sizeof(TS_FLOW)+7) & ~7);
Info->ClassMapContextLength = sizeof(PS_CLASS_MAP_CONTEXT);
Info->InitializePipe = TimeStmpInitializePipe;
Info->ModifyPipe = TimeStmpModifyPipe;
Info->DeletePipe = TimeStmpDeletePipe;
Info->CreateFlow = TimeStmpCreateFlow;
Info->ModifyFlow = TimeStmpModifyFlow;
Info->DeleteFlow = TimeStmpDeleteFlow;
Info->EmptyFlow = TimeStmpEmptyFlow;
Info->CreateClassMap = TimeStmpCreateClassMap;
Info->DeleteClassMap = TimeStmpDeleteClassMap;
Info->SubmitPacket = TimeStmpSubmitPacket;
Info->ReceivePacket = NULL;
Info->ReceiveIndication = NULL;
Info->SetInformation = TimeStmpSetInformation;
Info->QueryInformation = TimeStmpQueryInformation;
NdisAllocateSpinLock(&TsSpinLock);
InitializeListHead( &TsList );
TsCount = 0;
}
NDIS_STATUS
TimeStmpInitializePipe (
IN HANDLE PsPipeContext,
IN PPS_PIPE_PARAMETERS PipeParameters,
IN PPS_PIPE_CONTEXT ComponentPipeContext,
IN PPS_PROCS PsProcs,
IN PPS_UPCALLS Upcalls
)
{
PPS_PIPE_CONTEXT Pipe = ComponentPipeContext;
return (*Pipe->NextComponent->InitializePipe)(
PsPipeContext,
PipeParameters,
Pipe->NextComponentContext,
PsProcs,
Upcalls);
}
NDIS_STATUS
TimeStmpModifyPipe (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_PIPE_PARAMETERS PipeParameters
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
return (*Pipe->NextComponent->ModifyPipe)(
Pipe->NextComponentContext, PipeParameters);
}
VOID
TimeStmpDeletePipe (
IN PPS_PIPE_CONTEXT PipeContext
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
(*Pipe->NextComponent->DeletePipe)(Pipe->NextComponentContext);
}
NDIS_STATUS
TimeStmpCreateFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN HANDLE PsFlowContext,
IN PCO_CALL_PARAMETERS CallParameters,
IN PPS_FLOW_CONTEXT ComponentFlowContext
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
return (*Pipe->NextComponent->CreateFlow)(
Pipe->NextComponentContext,
PsFlowContext,
CallParameters,
ComponentFlowContext->NextComponentContext);
}
NDIS_STATUS
TimeStmpModifyFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PCO_CALL_PARAMETERS CallParameters
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
return (*Pipe->NextComponent->ModifyFlow)(
Pipe->NextComponentContext,
FlowContext->NextComponentContext,
CallParameters);
}
VOID
TimeStmpDeleteFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
(*Pipe->NextComponent->DeleteFlow)(
Pipe->NextComponentContext,
FlowContext->NextComponentContext);
}
VOID
TimeStmpEmptyFlow (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
(*Pipe->NextComponent->EmptyFlow)(
Pipe->NextComponentContext,
FlowContext->NextComponentContext);
}
VOID
TimeStmpSetInformation (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN NDIS_OID Oid,
IN ULONG Len,
IN void *Data)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
PPS_FLOW_CONTEXT Flow = FlowContext;
(*Pipe->NextComponent->SetInformation)(
Pipe->NextComponentContext,
(Flow)?Flow->NextComponentContext:0,
Oid,
Len,
Data);
}
VOID
TimeStmpQueryInformation (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN NDIS_OID Oid,
IN ULONG Len,
IN PVOID Data,
IN OUT PULONG BytesWritten,
IN OUT PULONG BytesNeeded,
IN OUT PNDIS_STATUS Status)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
PPS_FLOW_CONTEXT Flow = FlowContext;
(*Pipe->NextComponent->QueryInformation)(
Pipe->NextComponentContext,
(Flow)?Flow->NextComponentContext:0,
Oid,
Len,
Data,
BytesWritten,
BytesNeeded,
Status);
}
NDIS_STATUS
TimeStmpCreateClassMap (
IN PPS_PIPE_CONTEXT PipeContext,
IN HANDLE PsClassMapContext,
IN PTC_CLASS_MAP_FLOW ClassMap,
IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
)
{
return (*PipeContext->NextComponent->CreateClassMap)(
PipeContext->NextComponentContext,
PsClassMapContext,
ClassMap,
ComponentClassMapContext->NextComponentContext);
}
NDIS_STATUS
TimeStmpDeleteClassMap (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
)
{
return (*PipeContext->NextComponent->DeleteClassMap)(
PipeContext->NextComponentContext,
ComponentClassMapContext->NextComponentContext);
}
/* Routine Description:
Checks to see if there is any application requesting time-stamping for these end-points
Return Value:
MARK_NONE, MARK_IN_PKT, MARK_IN_BUF
*/
int
CheckForMatch( ULONG SrcIp,
ULONG DstIp,
USHORT SrcPort,
USHORT DstPort,
USHORT Proto,
USHORT IpId,
USHORT Size,
USHORT Direction)
{
PLIST_ENTRY ListEntry;
PTS_ENTRY pEntry;
int Status = MARK_NONE;
NdisAcquireSpinLock(&TsSpinLock);
ListEntry = TsList.Flink;
while (ListEntry != &TsList)
{
pEntry = CONTAINING_RECORD(ListEntry, TS_ENTRY, Linkage);
if( ((pEntry->SrcIp == UL_ANY) || (pEntry->SrcIp == SrcIp)) &&
((pEntry->SrcPort== US_ANY) || (pEntry->SrcPort == SrcPort)) &&
((pEntry->DstIp == UL_ANY) || (pEntry->DstIp == DstIp)) &&
((pEntry->DstPort == US_ANY) || (pEntry->DstPort == DstPort)) &&
((pEntry->Direction == US_ANY) || (pEntry->Direction == Direction)) &&
((pEntry->Proto == US_ANY) || (pEntry->Proto == Proto)))
{
if(pEntry->Type == MARK_IN_BUF)
{
LARGE_INTEGER PerfFrequency, CurrentTime;
UINT64 RecdTime, Freq;
MARK_IN_BUF_RECORD Record, *pRecord;
Status = MARK_IN_BUF;
if((int)( (char*)pEntry->pPacketStore - (char*)pEntry->pPacketStoreHead
+ sizeof(MARK_IN_BUF_RECORD) ) < PACKET_STORE_SIZE )
{
pEntry->pPacketStore->IpId = IpId;
pEntry->pPacketStore->Size = Size;
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
// Convert the perffrequency into 100ns interval. //
Freq = 0;
Freq |= PerfFrequency.HighPart;
Freq = Freq << 32;
Freq |= PerfFrequency.LowPart;
pEntry->pPacketStore->TimeValue = 0;
pEntry->pPacketStore->TimeValue |= CurrentTime.HighPart;
pEntry->pPacketStore->TimeValue = pEntry->pPacketStore->TimeValue << 32;
pEntry->pPacketStore->TimeValue |= CurrentTime.LowPart;
// Normalize cycles with the frequency //
pEntry->pPacketStore->TimeValue *= 10000000;
pEntry->pPacketStore->TimeValue /= Freq;
pEntry->pPacketStore = (PMARK_IN_BUF_RECORD)((char*)pEntry->pPacketStore + sizeof(MARK_IN_BUF_RECORD));
}
else
{
pEntry->pPacketStore = pEntry->pPacketStoreHead;
}
NdisReleaseSpinLock(&TsSpinLock);
return Status;
}
else if(pEntry->Type == MARK_IN_PKT)
{
Status = MARK_IN_PKT;
NdisReleaseSpinLock(&TsSpinLock);
return Status;
}
}
else
{
ListEntry = ListEntry->Flink;
}
}
NdisReleaseSpinLock(&TsSpinLock);
return Status;
}
/* Routine Description:
Adds an end-point to the list of monitoring end-points
Return Value:
TRUE, FALSE
*/
BOOL
AddRequest( PFILE_OBJECT FileObject,
ULONG SrcIp,
USHORT SrcPort,
ULONG DstIp,
USHORT DstPort,
USHORT Proto,
USHORT Type,
USHORT Direction)
{
PTS_ENTRY pEntry = NULL;
PsAllocatePool(pEntry, sizeof(TS_ENTRY), TsTag);
if( !pEntry )
return FALSE;
InitializeListHead(&pEntry->Linkage);
pEntry->SrcIp = SrcIp;
pEntry->SrcPort = SrcPort;
pEntry->DstIp = DstIp;
pEntry->DstPort = DstPort;
pEntry->Proto = Proto;
pEntry->Type = Type;
pEntry->Direction = Direction;
pEntry->FileObject = FileObject;
pEntry->pPacketStore = NULL;
pEntry->pPacketStoreHead = NULL;
if(Type == MARK_IN_BUF)
{
PsAllocatePool( pEntry->pPacketStoreHead, PACKET_STORE_SIZE, TsTag );
if( !pEntry->pPacketStoreHead)
{
PsFreePool( pEntry );
return FALSE;
}
pEntry->pPacketStore = pEntry->pPacketStoreHead;
}
NdisAcquireSpinLock(&TsSpinLock);
/* Need to check for duplication ..*/
InsertHeadList(&TsList, &pEntry->Linkage);
InterlockedIncrement( &TsCount );
NdisReleaseSpinLock(&TsSpinLock);
return TRUE;
}
/* Routine Description:
Removes an end-point to the list of monitoring end-points
Return Value:
None
Note:
Here, 0xffffffff means, wild card => Don't have to match on that field */
void
RemoveRequest( PFILE_OBJECT FileObject,
ULONG SrcIp,
USHORT SrcPort,
ULONG DstIp,
USHORT DstPort,
USHORT Proto)
{
PLIST_ENTRY ListEntry;
PTS_ENTRY pEntry;
NdisAcquireSpinLock(&TsSpinLock);
ListEntry = TsList.Flink;
while (ListEntry != &TsList)
{
pEntry = CONTAINING_RECORD(ListEntry, TS_ENTRY, Linkage);
if( ((FileObject == ULongToPtr(UL_ANY)) || (pEntry->FileObject == FileObject)) &&
((SrcIp == UL_ANY) || (pEntry->SrcIp == SrcIp)) &&
((SrcPort == US_ANY) || (pEntry->SrcPort == SrcPort)) &&
((DstIp == UL_ANY) || (pEntry->DstIp == DstIp)) &&
((DstPort == US_ANY) || (pEntry->DstPort == SrcPort)) &&
((Proto== US_ANY) || (pEntry->Proto == Proto)))
{
RemoveEntryList(&pEntry->Linkage);
if( pEntry->pPacketStoreHead)
PsFreePool( pEntry->pPacketStoreHead );
PsFreePool( pEntry );
InterlockedDecrement( &TsCount );
/* Need to go back to the beginning of the list againg.. */
ListEntry = TsList.Flink;
}
else
{
ListEntry = ListEntry->Flink;
}
}
NdisReleaseSpinLock(&TsSpinLock);
}
int
CopyTimeStmps( PFILE_OBJECT FileObject, PVOID buf, ULONG Len)
{
PLIST_ENTRY ListEntry;
PTS_ENTRY pEntry;
ULONG DataLen;
LARGE_INTEGER LargeLen;
if( Len < PACKET_STORE_SIZE )
return 0;
NdisAcquireSpinLock(&TsSpinLock);
ListEntry = TsList.Flink;
while (ListEntry != &TsList)
{
pEntry = CONTAINING_RECORD(ListEntry, TS_ENTRY, Linkage);
if( pEntry->FileObject == FileObject)
{
// Copy the data across and rest the pointers.. //
LargeLen.QuadPart = ((char*)pEntry->pPacketStore) - ((char*)pEntry->pPacketStoreHead);
DataLen = LargeLen.LowPart;
NdisMoveMemory( buf, pEntry->pPacketStoreHead, DataLen);
pEntry->pPacketStore = pEntry->pPacketStoreHead;
NdisReleaseSpinLock(&TsSpinLock);
return DataLen;
}
else
{
ListEntry = ListEntry->Flink;
}
}
NdisReleaseSpinLock(&TsSpinLock);
return 0;
}
VOID
UnloadTimeStmp( )
{
// Clear all the Requests //
RemoveRequest( ULongToPtr(UL_ANY),
UL_ANY,
US_ANY,
UL_ANY,
US_ANY,
US_ANY);
// Free the spin lock //
NdisFreeSpinLock(&TsSpinLock);
}
BOOLEAN
TimeStmpSubmitPacket (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
IN PPACKET_INFO_BLOCK PacketInfo
)
{
PTS_PIPE Pipe = (PTS_PIPE)PipeContext;
PTS_FLOW Flow = (PTS_FLOW)FlowContext;
PNDIS_PACKET Packet = PacketInfo->NdisPacket;
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;
if( (TsCount == 0) ||
(NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) != NDIS_PROTOCOL_ID_TCP_IP))
{
goto SUBMIT_NEXT;
}
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;
ULONG TransportHeaderOffset = 0;
TransportHeaderOffset = PacketInfo->IPHeaderOffset;
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)
goto SUBMIT_NEXT;
/* Let's try to parse the packet */
Src = IPH->iph_src;
Dst = IPH->iph_dest;
IPID = net_short(IPH->iph_id);
Size = net_short(IPH->iph_length);
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 )
goto SUBMIT_NEXT;
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)
goto SUBMIT_NEXT;
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);
// We have the TCP Buffer now. Get to the DATA //
TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
if (TcpLen > TcpHeaderOffset)
{
// We have the DATA right here! //
Data = (PUCHAR)TCPH + TcpHeaderOffset;
DataLen = TcpLen - TcpHeaderOffset;
}
else
{
NdisGetNextBuffer(TcpBuf, &DataBuf);
if(!DataBuf)
goto SUBMIT_NEXT;
GeneralVA = NULL;
NdisQueryBuffer(DataBuf,
&Data,
&DataLen
);
}
/* At this point, DataBuf, Data and DataLen contain the proper values */
goto TimeStamp;
break;
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)
goto SUBMIT_NEXT;
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);
// Get to the data. //
if (UdpLen > sizeof (UDPHeader))
{
// We have the DATA right here! //
Data = (PUCHAR) UDPH + sizeof (UDPHeader);
DataLen = UdpLen - sizeof (UDPHeader);
}
else
{
NdisGetNextBuffer(UdpBuf, &DataBuf);
if(!DataBuf)
goto SUBMIT_NEXT;
GeneralVA = NULL;
NdisQueryBuffer(DataBuf,
&Data,
&DataLen
);
}
/* At this point, DataBuf, Data and DataLen contain the proper values */
goto TimeStamp;
break;
default:
goto SUBMIT_NEXT;
}
TimeStamp:
Ret = CheckForMatch( Src, Dst, SrcPort, DstPort, IPH->iph_protocol, IPID, Size, DIR_SEND);
if( Ret == MARK_IN_PKT)
{
if (DataLen >= sizeof(MARK_IN_PKT_RECORD))
{
LARGE_INTEGER PerfFrequency, CurrentTime;
UINT64 RecdTime, Freq;
PMARK_IN_PKT_RECORD pRecord;
pRecord = (PMARK_IN_PKT_RECORD) Data;
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
pRecord->BufferSize = DataLen;
// Convert the perffrequency into 100ns interval //
Freq = 0;
Freq |= PerfFrequency.HighPart;
Freq = Freq << 32;
Freq |= PerfFrequency.LowPart;
// convert to uint64 //
pRecord->TimeSentWire = 0;
pRecord->TimeSentWire |= CurrentTime.HighPart;
pRecord->TimeSentWire = pRecord->TimeSentWire << 32;
pRecord->TimeSentWire |= CurrentTime.LowPart;
// Normalize cycles with the frequency.
pRecord->TimeSentWire *= 10000000;
pRecord->TimeSentWire /= Freq;
if(IPH->iph_protocol == IPPROTO_UDP)
UDPH->uh_xsum = 0;
}
}
else if( Ret == MARK_IN_BUF)
{
// Nothing more to be done..
}
SUBMIT_NEXT:
return (*Pipe->ContextInfo.NextComponent->SubmitPacket)(
Pipe->ContextInfo.NextComponentContext,
Flow->ContextInfo.NextComponentContext,
(ClassMapContext != NULL) ? ClassMapContext->NextComponentContext : NULL,
PacketInfo);
}
BOOLEAN
TimeStmpReceivePacket (
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
IN PNDIS_PACKET Packet,
IN NDIS_MEDIUM Medium
)
{
PPS_PIPE_CONTEXT Pipe;
LARGE_INTEGER CurrentTime;
IPHeader UNALIGNED *IPH;
TCPHeader UNALIGNED *TCPH;
UDPHeader UNALIGNED *UDPH;
IPAddr Src, Dst;
PUCHAR headerBuffer, pData;
PNDIS_BUFFER pFirstBuffer;
ULONG firstbufferLength, bufferLength, HeaderLength;
ULONG TotalIpLen, IPDataLength, IpHdrLen;
ULONG TotalTcpLen, TcpDataLen, TotalLen, TcpHeaderOffset, i;
int TotalUdpLen, UdpDataLen, UdpHdrLen, DataLen, Ret;
USHORT SrcPort, DstPort, IPID, FragOffset, Size;
BOOLEAN bFragment, bFirstFragment, bLastFragment;
/* This will give the size of the "media-specific" header. So, this will be the offset to IP packet */
UINT HeaderBufferSize ;
ushort type; // Protocol type
uint ProtOffset; // Offset in Data to non-media info.
if( ( TsCount == 0) ||
(NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) == NDIS_PROTOCOL_ID_TCP_IP))
{
return TRUE;
}
Pipe = PipeContext;
HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
NdisGetFirstBufferFromPacket(Packet, // packet
&pFirstBuffer, // first buffer descriptor
&headerBuffer, // VA of the first buffer
&firstbufferLength, // length of the header+lookahead
&bufferLength); // length of the bytes in the buffers
IPH = (IPHeader *) ((PUCHAR)headerBuffer + HeaderBufferSize);
// Check the header length and the version //
HeaderLength = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
// If the HeaderLength seems to be incorrect, let's not try to parse //
if( (HeaderLength < sizeof(IPHeader)) ||
(HeaderLength > bufferLength) )
return TRUE;
// Get past the IP Header and get the rest of the stuff out //
TotalIpLen = (uint)net_short(IPH->iph_length);
// Make sure the version and IpData Len are correct //
if( ((IPH->iph_verlen & IP_VER_FLAG) != IP_VERSION ) ||
( TotalIpLen < HeaderLength ) ||
( TotalIpLen > bufferLength ))
return TRUE;
// Let's try to parse the packet //
Src = IPH->iph_src;
Dst = IPH->iph_dest;
IPID = net_short(IPH->iph_id);
Size = net_short(IPH->iph_length);
FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
FragOffset = net_short(FragOffset) * 8;
bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
bFirstFragment = bFragment && (FragOffset == 0);
bLastFragment = bFragment && (!(IPH->iph_offset & IP_MF_FLAG));
// If this is a fragment and NOT the first one, just put the Timestamp in here.
// Otherwise, let it get to the protocols for processing.
if (bFragment )
return TRUE;
// Do the protocol specific stuff //
switch (IPH->iph_protocol)
{
case IPPROTO_TCP:
TotalTcpLen = TotalIpLen - HeaderLength;
TCPH = (TCPHeader *) (((PUCHAR)IPH) + HeaderLength);
// For TCP, the data offset is part of the TCP Header */
TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
DataLen = TotalTcpLen - TcpHeaderOffset;
pData = (PUCHAR) TCPH + TcpHeaderOffset;
SrcPort = net_short(TCPH->tcp_src);
DstPort = net_short(TCPH->tcp_dest);
goto TimeStmp;
break;
case IPPROTO_UDP:
TotalUdpLen = TotalIpLen - HeaderLength;
UDPH = (UDPHeader *) (((PUCHAR)IPH) + HeaderLength);
// For UDP, the header size is fixed //
DataLen = TotalUdpLen - sizeof(UDPHeader);
pData = ((PUCHAR) UDPH) + sizeof (UDPHeader);
SrcPort = net_short(UDPH->uh_src);
DstPort = net_short(UDPH->uh_dest);
goto TimeStmp;
break;
default:
break;
}
return TRUE;
TimeStmp:
Ret = CheckForMatch( Src, Dst, SrcPort, DstPort, IPH->iph_protocol, IPID, Size, DIR_RECV);
if( Ret == MARK_IN_PKT)
{
if (DataLen >= sizeof(MARK_IN_PKT_RECORD))
{
LARGE_INTEGER PerfFrequency, CurrentTime;
UINT64 RecdTime, Freq;
PMARK_IN_PKT_RECORD pRecord;
pRecord = (PMARK_IN_PKT_RECORD) pData;
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
// Convert the perffrequency into 100ns interval //
Freq = 0;
Freq |= PerfFrequency.HighPart;
Freq = Freq << 32;
Freq |= PerfFrequency.LowPart;
//convert from large_integer to uint64
pRecord->TimeReceivedWire = 0;
pRecord->TimeReceivedWire |= CurrentTime.HighPart;
pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
pRecord->TimeReceivedWire |= CurrentTime.LowPart;
// Normalize cycles with the frequency.
pRecord->TimeReceivedWire *= 10000000;
pRecord->TimeReceivedWire /= Freq;
if(IPH->iph_protocol == IPPROTO_UDP)
UDPH->uh_xsum = 0;
}
}
else if( Ret == MARK_IN_BUF)
{
}
return TRUE;
}
#ifdef NEVER
//
// This function receives a buffer from NDIS which is indicated to the transport.
// We use this function and work past the headers (tcp, ip) and get to the data.
// Then, we timestamp and reset the checksum flags.
// We make the assumption that the lookahead is atleast 128.
// mac header ~ 8+8, ip header ~20, tcp/udp ~ 20+options, LOG_RECORD ~ 44
// they all add up to less than 128. If this is not a good assumption, We will need
// to get into MiniportTransferData and such.
//
BOOLEAN
TimeStmpReceiveIndication(
IN PPS_PIPE_CONTEXT PipeContext,
IN PPS_FLOW_CONTEXT FlowContext,
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize,
IN UINT TransportHeaderOffset
)
{
PPS_PIPE_CONTEXT Pipe = PipeContext;
LARGE_INTEGER CurrentTime;
IPHeader UNALIGNED *IPH = NULL;
TCPHeader UNALIGNED *TCPH = NULL;
UDPHeader UNALIGNED *UDPH = NULL;
IPAddr Src, Dst;
PUCHAR headerBuffer = NULL, pData = NULL;
PNDIS_BUFFER pFirstBuffer = NULL;
ULONG firstbufferLength = 0, bufferLength = 0, HeaderLength = 0;
ULONG TotalIpLen = 0, IPDataLength = 0, IpHdrLen = 0;
ULONG TotalTcpLen = 0, TcpDataLen = 0, TotalLen = 0, TcpHeaderOffset = 0;
ULONG TotalUdpLen = 0, UdpDataLen = 0, UdpHdrLen = 0;
USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0, Size = 0;
BOOLEAN bFragment, bFirstFragment, bLastFragment;
ULONG i = 0;
ushort type; // Protocol type
uint ProtOffset; // Offset in Data to non-media info.
UINT MoreHeaderInLookAhead = 0;
// Don't know anything about the MAC headers, piggy back from PSCHED...
// Calculate if the header is more than the standard HeaderBufferSize (i.e. SNAP header, etc.)
//
MoreHeaderInLookAhead = TransportHeaderOffset - HeaderBufferSize;
if (MoreHeaderInLookAhead)
{
// Just munge these, so that we can actually get down to business //
((PUCHAR) LookAheadBuffer) += MoreHeaderInLookAhead;
LookAheadBufferSize -= MoreHeaderInLookAhead;
}
if (LookAheadBufferSize > sizeof(IPHeader))
{
IPH = (IPHeader *) (PUCHAR)LookAheadBuffer;
// Check the header length and the version. If any of these
// checks fail silently discard the packet.
HeaderLength = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
if (HeaderLength >= sizeof(IPHeader) && HeaderLength <= LookAheadBufferSize)
{
// Get past the IP Header and get the rest of the stuff out//
TotalIpLen = (uint)net_short(IPH->iph_length);
if ((IPH->iph_verlen & IP_VER_FLAG) == IP_VERSION &&
TotalIpLen >= HeaderLength && TotalIpLen <= LookAheadBufferSize)
{
Src = IPH->iph_src;
Dst = IPH->iph_dest;
IPID = net_short(IPH->iph_id);
Size = net_short(IPH->iph_length );
FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
FragOffset = net_short(FragOffset) * 8;
bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
bFirstFragment = bFragment && (FragOffset == 0);
bLastFragment = bFragment && (!(IPH->iph_offset & IP_MF_FLAG));
// If this is a fragment and NOT the first one, just put the Timestamp in here.
// Otherwise, let it get to the protocols for processing.
if (bFragment )
return TRUE;
// Do the protocol specific stuff.//
switch (IPH->iph_protocol)
{
case IPPROTO_TCP:
TotalTcpLen = TotalIpLen - HeaderLength;
TCPH = (TCPHeader *) (((PUCHAR)IPH) + HeaderLength);
SrcPort = net_short(TCPH->tcp_src);
DstPort = net_short(TCPH->tcp_dest);
TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
pData = (PUCHAR) TCPH + TcpHeaderOffset;
TcpDataLen = TotalTcpLen - TcpHeaderOffset;
goto TimeStmp;
break;
case IPPROTO_UDP:
TotalUdpLen = TotalIpLen - HeaderLength;
UDPH = (UDPHeader *) (((PUCHAR)IPH) + HeaderLength);
UdpDataLen = TotalUdpLen - sizeof(UDPHeader);
pData = ((PUCHAR) UDPH) + sizeof (UDPHeader);
SrcPort = net_short(UDPH->uh_src);
DstPort = net_short(UDPH->uh_dest);
if (UdpDataLen < sizeof(UDPHeader))
return TRUE;
goto TimeStmp;
break;
default:
break;
}
}
}
}
TimeStmp:
CheckForMatch( Src, Dst, SrcPort, DstPort,0, IPID, Size, DIR_RECV);
/*
if (CheckInPortAndIpList(Src, DstPort))
{
LARGE_INTEGER PerfFrequency;
UINT64 RecdTime, Freq;
LOG_RECORD Record;
pRecord = &Record;
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
//
// Convert the perffrequency into 100ns interval.
//
Freq = 0;
Freq |= PerfFrequency.HighPart;
Freq = Freq << 32;
Freq |= PerfFrequency.LowPart;
pRecord->TimeReceivedWire = 0;
pRecord->TimeReceivedWire |= CurrentTime.HighPart;
pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
pRecord->TimeReceivedWire |= CurrentTime.LowPart;
// Normalize cycles with the frequency.
pRecord->TimeReceivedWire *= 10000000;
pRecord->TimeReceivedWire /= Freq;
if( (int)( (char*)pPacketStore - (char*)pPacketStoreHead + sizeof(PACKET_RECORD) ) < PACKET_STORE_SIZE )
{
pPacketStore->IpId = IPID;
pPacketStore->cSeperator1='y';
pPacketStore->TimeValue = pRecord->TimeReceivedWire;
pPacketStore->cSeperator2 = 'm';
pPacketStore->Size = Size;
pPacketStore->cSeperator3 = 'z';
pPacketStore->cSeperator4 = 'z';
pPacketStore = (PPACKET_RECORD)((char*)pPacketStore + sizeof(PACKET_RECORD));
}
else
{
pPacketStore = pPacketStoreHead;
}
}
*/
return TRUE;
}
#endif