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.
1816 lines
60 KiB
1816 lines
60 KiB
/*++
|
|
|
|
Copyright (c) 1996-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
timestmp.c
|
|
|
|
Abstract:
|
|
|
|
Timestamper module
|
|
|
|
Author:
|
|
Shreedhar Madhavapeddi (shreem)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <timestmp.h>
|
|
|
|
//
|
|
// The following struct has to be in ssync with
|
|
// ndis\trfccntl\tools\qtcp\qtcp.c
|
|
//
|
|
typedef struct _LOG_RECORD{
|
|
UINT64 TimeSent;
|
|
UINT64 TimeReceived;
|
|
UINT64 TimeSentWire; // These fields are used by the kernel timestamper
|
|
UINT64 TimeReceivedWire; // These fields are used by the kernel timestamper
|
|
UINT64 Latency;
|
|
INT BufferSize;
|
|
INT SequenceNumber;
|
|
} LOG_RECORD, *PLOG_RECORD;
|
|
|
|
ULONG GlobalSequenceNumber = 0;
|
|
|
|
// 321618 needs checking for PSCHED's existence.
|
|
NDIS_STRING PschedDriverName = NDIS_STRING_CONST("\\Device\\PSched");
|
|
HANDLE PschedHandle;
|
|
NTSTATUS CheckForPsched(VOID);
|
|
|
|
|
|
//
|
|
// TCP Headers (redefined here, since there are no exported headers
|
|
//
|
|
#define IP_OFFSET_MASK ~0x00E0 // Mask for extracting offset field.
|
|
#define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
|
|
|
|
/*
|
|
* Protocols (from winsock.h)
|
|
*/
|
|
#define IPPROTO_IP 0 /* dummy for IP */
|
|
#define IPPROTO_ICMP 1 /* control message protocol */
|
|
#define IPPROTO_IGMP 2 /* group management protocol */
|
|
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
|
|
#define IPPROTO_TCP 6 /* tcp */
|
|
#define IPPROTO_PUP 12 /* pup */
|
|
#define IPPROTO_UDP 17 /* user datagram protocol */
|
|
#define IPPROTO_IDP 22 /* xns idp */
|
|
#define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
|
|
#define IPPROTO_IPSEC 51 /* ???????? */
|
|
|
|
#define IPPROTO_RAW 255 /* raw IP packet */
|
|
#define IPPROTO_MAX 256
|
|
|
|
#define IP_MF_FLAG 0x0020 // 'More fragments flag'
|
|
#define IP_VERSION 0x40
|
|
#define IP_VER_FLAG 0xF0
|
|
|
|
|
|
#define TCP_OFFSET_MASK 0xf0
|
|
#define TCP_HDR_SIZE(t) (uint)(((*(uchar *)&(t)->tcp_flags) & TCP_OFFSET_MASK) >> 2)
|
|
|
|
typedef int SeqNum; // A sequence number.
|
|
|
|
|
|
struct TCPHeader {
|
|
ushort tcp_src; // Source port.
|
|
ushort tcp_dest; // Destination port.
|
|
SeqNum tcp_seq; // Sequence number.
|
|
SeqNum tcp_ack; // Ack number.
|
|
ushort tcp_flags; // Flags and data offset.
|
|
ushort tcp_window; // Window offered.
|
|
ushort tcp_xsum; // Checksum.
|
|
ushort tcp_urgent; // Urgent pointer.
|
|
};
|
|
|
|
typedef struct TCPHeader TCPHeader;
|
|
|
|
struct UDPHeader {
|
|
ushort uh_src; // Source port.
|
|
ushort uh_dest; // Destination port.
|
|
ushort uh_length; // Length
|
|
ushort uh_xsum; // Checksum.
|
|
}; /* UDPHeader */
|
|
|
|
typedef struct UDPHeader UDPHeader;
|
|
|
|
#ifdef DBG
|
|
//
|
|
// Define the Trace Level.
|
|
//
|
|
#define TS_DBG_DEATH 1
|
|
#define TS_DBG_TRACE 2
|
|
|
|
//
|
|
// Masks
|
|
//
|
|
#define TS_DBG_PIPE 0x00000001
|
|
#define TS_DBG_FLOW 0x00000002
|
|
#define TS_DBG_SEND 0x00000004
|
|
#define TS_DBG_RECV 0x00000008
|
|
#define TS_DBG_INIT 0x00000010
|
|
#define TS_DBG_OID 0x00000020
|
|
#define TS_DBG_CLASS_MAP 0x00000040
|
|
|
|
ULONG DbgTraceLevel = 1;
|
|
ULONG DbgTraceMask = 0x8;
|
|
|
|
#define TimeStmpTrace(_DebugLevel, _DebugMask, _Out) \
|
|
if ((DbgTraceLevel >= _DebugLevel) && \
|
|
((_DebugMask) & DbgTraceMask)){ \
|
|
DbgPrint("TimeStamp: "); \
|
|
DbgPrint _Out; \
|
|
}
|
|
|
|
#else // DBG
|
|
#define TimeStmpTrace
|
|
#endif
|
|
|
|
#define PORT_RANGE 20
|
|
USHORT IPIDList[PORT_RANGE];
|
|
NDIS_SPIN_LOCK IPIDListLock;
|
|
|
|
#define PORT_RANGE 20
|
|
USHORT IPIDListRecv[PORT_RANGE];
|
|
NDIS_SPIN_LOCK IPIDListLockRecv;
|
|
|
|
/*
|
|
Let's create a driver unload function, so that timestmp is stoppable via net sto
|
|
p timestmp
|
|
*/
|
|
VOID
|
|
TimeStmpUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
|
|
IoctlCleanup();
|
|
return;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_PIPE, ("[TimeStmpIndicatePipe]: \n"));
|
|
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;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_PIPE, ("[TimeStmpModifyPipe]: \n"));
|
|
return (*Pipe->NextComponent->ModifyPipe)(
|
|
Pipe->NextComponentContext, PipeParameters);
|
|
}
|
|
|
|
VOID
|
|
TimeStmpDeletePipe (
|
|
IN PPS_PIPE_CONTEXT PipeContext
|
|
)
|
|
{
|
|
PPS_PIPE_CONTEXT Pipe = PipeContext;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_PIPE, ("[TimeStmpDeletePipe]: \n"));
|
|
(*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;
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_FLOW, ("[TimeStmpCreateFlow]: \n"));
|
|
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;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_FLOW, ("[TimeStmpModifyFlow]: \n"));
|
|
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;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_FLOW, ("[TimeStmpDeleteFlow]: \n"));
|
|
(*Pipe->NextComponent->DeleteFlow)(
|
|
Pipe->NextComponentContext,
|
|
FlowContext->NextComponentContext);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
TimeStmpSubmitPacket (
|
|
IN PPS_PIPE_CONTEXT PipeContext,
|
|
IN PPS_FLOW_CONTEXT FlowContext,
|
|
IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
|
|
IN PPACKET_INFO_BLOCK PacketInfo
|
|
)
|
|
{
|
|
PPS_PIPE_CONTEXT Pipe = PipeContext;
|
|
LARGE_INTEGER CurrentTime;
|
|
IPHeader UNALIGNED *IPH = NULL;
|
|
TCPHeader UNALIGNED *TCPH = NULL;
|
|
UDPHeader UNALIGNED *UDPH = NULL;
|
|
PVOID ArpH = NULL, GeneralVA = NULL, Data = NULL;
|
|
IPAddr Src, Dst;
|
|
PNDIS_BUFFER ArpBuf = NULL, IpBuf = NULL, TcpBuf = NULL, DataBuf = NULL, UdpBuf = NULL;
|
|
ULONG ArpLen = 0, IpLen = 0, IpHdrLen = 0, TcpLen = 0, DataLen = 0, TotalLen = 0, TcpHeaderOffset = 0;
|
|
ULONG UdpLen = 0;
|
|
USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0;
|
|
PLIST_ENTRY CurrentEntry = NULL, LastEntry = NULL;
|
|
BOOLEAN bFragment, bFirstFragment, bLastFragment;
|
|
ULONG i = 0;
|
|
PLOG_RECORD pRecord = NULL;
|
|
PNDIS_PACKET Packet = PacketInfo->NdisPacket;
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: \n"));
|
|
|
|
//
|
|
// Steps
|
|
// Parse the IP Packet.
|
|
// Look for the appropriate ports.
|
|
// Look for the data portion and put in the Time & length there.
|
|
//
|
|
|
|
NdisGetFirstBufferFromPacket(
|
|
Packet,
|
|
&ArpBuf,
|
|
&ArpH,
|
|
&ArpLen,
|
|
&TotalLen
|
|
);
|
|
|
|
//
|
|
// We are guaranteed that the ARP buffer if always a different MDL, so
|
|
// jump to the next MDL
|
|
//
|
|
NdisGetNextBuffer(ArpBuf, &IpBuf)
|
|
|
|
if (IpBuf) {
|
|
|
|
NdisQueryBuffer(IpBuf,
|
|
&GeneralVA,
|
|
&IpLen
|
|
);
|
|
|
|
IPH = (IPHeader *) GeneralVA;
|
|
|
|
if (!IPH) {
|
|
goto FAILURE;
|
|
}
|
|
|
|
Src = net_short(IPH->iph_src);
|
|
Dst = net_short(IPH->iph_dest);
|
|
IPID = net_short(IPH->iph_id);
|
|
//IpHdrLen = 8 * 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);
|
|
bFirstFragment = bFragment && (FragOffset == 0);
|
|
bLastFragment = bFragment && (!(IPH->iph_offset & IP_MF_FLAG));
|
|
|
|
if (bFragment && (!bFirstFragment)) {
|
|
|
|
//
|
|
// Its a fragment alright and NOT the first one.
|
|
//
|
|
NdisAcquireSpinLock(&IPIDListLock);
|
|
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
|
|
//
|
|
// Found the match...
|
|
//
|
|
if (IPIDList[i] == IPID) {
|
|
|
|
if (bLastFragment) {
|
|
//
|
|
// Since it is the last fragment, recall
|
|
// the IP ID.
|
|
//
|
|
IPIDList[i] = 0xffff;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLock);
|
|
|
|
//
|
|
// Is the data in the same buffer?
|
|
//
|
|
if (IpLen <= IpHdrLen) {
|
|
|
|
NdisGetNextBuffer(IpBuf, &DataBuf);
|
|
|
|
if(DataBuf) {
|
|
|
|
NdisQueryBuffer(DataBuf,
|
|
&Data,
|
|
&DataLen
|
|
);
|
|
|
|
goto TimeStamp;
|
|
|
|
} else {
|
|
|
|
goto FAILURE;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// The Data Offsets need to be primed now.
|
|
//
|
|
DataLen = IpLen - FragOffset;
|
|
Data = ((PUCHAR) GeneralVA) + IpHdrLen;
|
|
goto TimeStamp;
|
|
}
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLock);
|
|
//
|
|
// If we are here, we dont care about this IPID for this fragment.
|
|
// Just return TRUE to continue processing.
|
|
//
|
|
|
|
//
|
|
// Ready to go.
|
|
//
|
|
PacketInfo->FlowContext = FlowContext;
|
|
PacketInfo->ClassMapContext = ClassMapContext;
|
|
|
|
return (*Pipe->NextComponent->SubmitPacket)(
|
|
Pipe->NextComponentContext,
|
|
FlowContext->NextComponentContext,
|
|
ClassMapContext?ClassMapContext->NextComponentContext:0,
|
|
PacketInfo);
|
|
|
|
}
|
|
|
|
//
|
|
// If it is not a fragment, depending upon the protocol, process differently
|
|
//
|
|
|
|
switch (IPH->iph_protocol) {
|
|
|
|
case IPPROTO_TCP :
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Procol TCP\n"));
|
|
|
|
if (IPH && ((USHORT)IpLen > IpHdrLen)) {
|
|
|
|
//
|
|
// We have more than the IP Header in this MDL.
|
|
//
|
|
TCPH = (TCPHeader *) ((PUCHAR)GeneralVA + IpHdrLen);
|
|
TcpLen = IpLen - IpHdrLen;
|
|
TcpBuf = IpBuf;
|
|
|
|
} else {
|
|
|
|
//
|
|
// TCP Header is in the next MDL
|
|
//
|
|
|
|
NdisGetNextBuffer(IpBuf, &TcpBuf);
|
|
|
|
if(TcpBuf) {
|
|
|
|
GeneralVA = NULL;
|
|
NdisQueryBuffer(TcpBuf,
|
|
&GeneralVA,
|
|
&TcpLen
|
|
);
|
|
|
|
TCPH = (TCPHeader *) GeneralVA;
|
|
} else {
|
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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) {
|
|
|
|
GeneralVA = NULL;
|
|
NdisQueryBuffer(DataBuf,
|
|
&Data,
|
|
&DataLen
|
|
);
|
|
|
|
} else {
|
|
|
|
goto FAILURE;
|
|
}
|
|
}
|
|
|
|
if (CheckInPortList(DstPort) && bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLock);
|
|
|
|
// need new Entry for IPID
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
//
|
|
// Look for a free slot
|
|
//
|
|
if (0xffff == IPIDList[i]) {
|
|
|
|
IPIDList[i] = IPID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLock);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_SEND, ("Couldn't find an empty IPID - Bailing \n"));
|
|
goto FAILURE;
|
|
}
|
|
//DbgBreakPoint();
|
|
|
|
}
|
|
|
|
//
|
|
// Let's timestmp this now.
|
|
//
|
|
if (CheckInPortList(DstPort)) {
|
|
|
|
goto TimeStamp;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This is not one of our packet, get out.
|
|
//
|
|
goto FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol UDP\n"));
|
|
|
|
if (IPH && (IpLen > IpHdrLen)) {
|
|
|
|
//
|
|
// We have more than the IP Header in this MDL.
|
|
//
|
|
UDPH = (UDPHeader *) ((PUCHAR)GeneralVA + IpHdrLen);
|
|
UdpLen = IpLen - IpHdrLen;
|
|
UdpBuf = IpBuf;
|
|
|
|
} else {
|
|
|
|
//
|
|
// UDP Header is in the next MDL
|
|
//
|
|
|
|
NdisGetNextBuffer(IpBuf, &UdpBuf);
|
|
|
|
if(UdpBuf) {
|
|
|
|
GeneralVA = NULL;
|
|
NdisQueryBuffer(UdpBuf,
|
|
&GeneralVA,
|
|
&UdpLen
|
|
);
|
|
|
|
UDPH = (UDPHeader *) GeneralVA;
|
|
} else {
|
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
}
|
|
|
|
SrcPort = net_short(UDPH->uh_src); // Source port.
|
|
DstPort = net_short(UDPH->uh_dest); // Destination port.
|
|
|
|
|
|
//
|
|
// 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) {
|
|
|
|
GeneralVA = NULL;
|
|
NdisQueryBuffer(DataBuf,
|
|
&Data,
|
|
&DataLen
|
|
);
|
|
|
|
} else {
|
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (CheckInPortList(DstPort) && bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLock);
|
|
|
|
// need new Entry for IPID
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
//
|
|
// Look for a free slot
|
|
//
|
|
if (0xffff == IPIDList[i]) {
|
|
|
|
IPIDList[i] = IPID;
|
|
break;
|
|
|
|
}
|
|
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLock);
|
|
|
|
//
|
|
// Couldnt find a free IPID place holder, lets bail.
|
|
//
|
|
if (PORT_RANGE == i) {
|
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Let's timestmp this now.
|
|
//
|
|
if (CheckInPortList(DstPort)) {
|
|
|
|
goto TimeStamp;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This is not one of our packet, get out.
|
|
//
|
|
goto FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_RAW:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol RAW\n"));
|
|
goto FAILURE;
|
|
|
|
break;
|
|
|
|
case IPPROTO_IGMP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol IGMP\n"));
|
|
goto FAILURE;
|
|
|
|
break;
|
|
|
|
case IPPROTO_ICMP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol TCMP\n"));
|
|
goto FAILURE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//TimeStmpTrace(TS_DBG_DEATH, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol - UNKNOWN (%d)\n", IPH->iph_protocol));
|
|
goto FAILURE;
|
|
|
|
//DbgBreakPoint();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: NO Buffer beyond MAC Header\n"));
|
|
goto FAILURE;
|
|
|
|
}
|
|
|
|
TimeStamp:
|
|
//
|
|
// If we get here, the Data and DataLen variables have been primed.
|
|
// Set the Time and Length.
|
|
//
|
|
if (Data) {
|
|
|
|
pRecord = (PLOG_RECORD) Data;
|
|
|
|
if (DataLen > sizeof (LOG_RECORD)) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 Freq;
|
|
|
|
//
|
|
// Set the fields accordingly
|
|
pRecord->BufferSize = DataLen;
|
|
//pRecord->SequenceNumber = InterlockedIncrement(&GlobalSequenceNumber);
|
|
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->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;
|
|
|
|
}
|
|
|
|
}
|
|
//
|
|
// Ready to go.
|
|
//
|
|
PacketInfo->FlowContext = FlowContext;
|
|
PacketInfo->ClassMapContext = ClassMapContext;
|
|
|
|
return (*Pipe->NextComponent->SubmitPacket)(
|
|
Pipe->NextComponentContext,
|
|
FlowContext->NextComponentContext,
|
|
ClassMapContext?ClassMapContext->NextComponentContext:0,
|
|
PacketInfo);
|
|
|
|
FAILURE:
|
|
|
|
//
|
|
// Ready to go.
|
|
//
|
|
PacketInfo->FlowContext = FlowContext;
|
|
PacketInfo->ClassMapContext = ClassMapContext;
|
|
|
|
return (*Pipe->NextComponent->SubmitPacket)(
|
|
Pipe->NextComponentContext,
|
|
FlowContext->NextComponentContext,
|
|
ClassMapContext?ClassMapContext->NextComponentContext:0,
|
|
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 = 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, Size = 0;
|
|
ULONG TotalUdpLen = 0, UdpDataLen = 0, UdpHdrLen = 0;
|
|
USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0;
|
|
BOOLEAN bFragment, bFirstFragment, bLastFragment;
|
|
ULONG i = 0;
|
|
PLOG_RECORD pRecord = NULL;
|
|
UINT HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
|
|
|
|
ushort type; // Protocol type
|
|
uint ProtOffset; // Offset in Data to non-media info.
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: \n"));
|
|
|
|
NdisGetFirstBufferFromPacket(Packet, // packet
|
|
&pFirstBuffer, // first buffer descriptor
|
|
&headerBuffer, // ptr to the start of packet
|
|
&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. If any of these
|
|
// checks fail silently discard the packet.
|
|
HeaderLength = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
|
|
|
|
|
|
if (HeaderLength >= sizeof(IPHeader) && HeaderLength <= bufferLength) {
|
|
|
|
//
|
|
// 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 <= bufferLength) {
|
|
|
|
Src = net_short(IPH->iph_src);
|
|
Dst = net_short(IPH->iph_dest);
|
|
IPID = net_short(IPH->iph_id);
|
|
|
|
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 && !bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLockRecv);
|
|
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
|
|
if (IPID == IPIDListRecv[i]) {
|
|
|
|
if (bLastFragment) {
|
|
//
|
|
// If its the last fragment, release the slot.
|
|
//
|
|
IPIDListRecv[i] = 0xffff;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLockRecv);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldnt find an IPID that we care about, get outta here.\n"));
|
|
goto RECV_FAILURE;
|
|
|
|
}
|
|
//
|
|
// So we found a IPID that matches - set the timestamp and get out after this.
|
|
//
|
|
|
|
TotalLen = TotalIpLen - FragOffset;
|
|
pData = ((PUCHAR) IPH) + IpHdrLen;
|
|
|
|
if (TotalLen > sizeof (LOG_RECORD)) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 RecdTime, Freq;
|
|
|
|
pRecord = (LOG_RECORD *) pData;
|
|
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
|
|
|
|
//
|
|
// Convert the perffrequency into 100ns interval.
|
|
//
|
|
Freq = 0;
|
|
Freq |= PerfFrequency.HighPart;
|
|
Freq = Freq << 32;
|
|
Freq |= PerfFrequency.LowPart;
|
|
|
|
//convert from Largeinteger 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;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: *TCP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
|
|
IPH->iph_src,
|
|
IPH->iph_dest,
|
|
SrcPort,
|
|
DstPort));
|
|
|
|
TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
|
|
pData = (PUCHAR) TCPH + TcpHeaderOffset;
|
|
TcpDataLen = TotalTcpLen - TcpHeaderOffset;
|
|
|
|
if ((CheckInPortList(DstPort)) && (TcpDataLen > sizeof (LOG_RECORD))) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 RecdTime, Freq;
|
|
|
|
pRecord = (LOG_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;
|
|
|
|
|
|
} else if (CheckInPortList(DstPort)) {
|
|
|
|
if (TcpDataLen < sizeof(LOG_RECORD))
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("The Datagram was too small!! IpLen:%d, Tcplen:%d HeaderOff(tcp):%d log_record:%d\n", TotalIpLen, TotalTcpLen, TcpHeaderOffset, sizeof (LOG_RECORD)));
|
|
|
|
}
|
|
|
|
//
|
|
// If its the first fragment, keep a place holder so we know which
|
|
// subsequent IP fragments to timestamp.
|
|
//
|
|
if ((CheckInPortList(DstPort)) && bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLockRecv);
|
|
|
|
// need new Entry for IPID
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
//
|
|
// Look for a free slot
|
|
//
|
|
if (0xffff == IPIDListRecv[i]) {
|
|
|
|
IPIDListRecv[i] = IPID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLockRecv);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
TotalUdpLen = TotalIpLen - HeaderLength;
|
|
UDPH = (UDPHeader *) (((PUCHAR)IPH) + HeaderLength);
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("PAcket %x, IPH = %x, UDPH = %x, HeaderLength = %x\n", Packet, IPH, UDPH, HeaderLength));
|
|
|
|
UdpDataLen = TotalUdpLen - sizeof(UDPHeader);
|
|
pData = ((PUCHAR) UDPH) + sizeof (UDPHeader);
|
|
|
|
SrcPort = net_short(UDPH->uh_src); // Source port.
|
|
DstPort = net_short(UDPH->uh_dest); // Destination port.
|
|
|
|
if (UdpDataLen < sizeof(UDPHeader)) {
|
|
return TRUE;
|
|
}
|
|
|
|
if ((CheckInPortList(DstPort)) && (UdpDataLen > sizeof(LOG_RECORD))) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 RecdTime, Freq;
|
|
|
|
pRecord = (LOG_RECORD *) pData;
|
|
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
|
|
|
|
//
|
|
// Convert the perffrequency into 100ns interval.
|
|
//
|
|
Freq = 0;
|
|
Freq |= PerfFrequency.HighPart;
|
|
Freq = Freq << 32;
|
|
Freq |= PerfFrequency.LowPart;
|
|
|
|
// convert 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;
|
|
|
|
|
|
//
|
|
// Dont want to get rejected due to bad xsum ...
|
|
//
|
|
UDPH->uh_xsum = 0;
|
|
|
|
} else if (CheckInPortList(DstPort)) {
|
|
|
|
if ((UdpDataLen) < sizeof(LOG_RECORD))
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("The Datagram was too small (UDP)!! IpLen:%d, Size:%d log_record:%d\n",
|
|
TotalIpLen, UdpDataLen, sizeof (LOG_RECORD)));
|
|
|
|
}
|
|
|
|
if ((CheckInPortList(DstPort)) && bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLockRecv);
|
|
|
|
// need new Entry for IPID
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
//
|
|
// Look for a free slot
|
|
//
|
|
if (0xffff == IPIDListRecv[i]) {
|
|
|
|
IPIDListRecv[i] = IPID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLockRecv);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
|
|
}
|
|
}
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: *UDP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
|
|
IPH->iph_src,
|
|
IPH->iph_dest,
|
|
UDPH->uh_src,
|
|
UDPH->uh_dest));
|
|
|
|
break;
|
|
|
|
case IPPROTO_RAW:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol RAW\n"));
|
|
|
|
break;
|
|
|
|
case IPPROTO_IGMP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol IGMP\n"));
|
|
|
|
break;
|
|
|
|
case IPPROTO_ICMP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol TCMP\n"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
//TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol - UNKNOWN (%d)\n", IPH->iph_protocol));
|
|
//DbgBreakPoint();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
RECV_FAILURE:
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// 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, Size = 0;
|
|
ULONG TotalUdpLen = 0, UdpDataLen = 0, UdpHdrLen = 0;
|
|
USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0;
|
|
BOOLEAN bFragment, bFirstFragment, bLastFragment;
|
|
ULONG i = 0;
|
|
PLOG_RECORD pRecord = NULL;
|
|
ushort type; // Protocol type
|
|
uint ProtOffset; // Offset in Data to non-media info.
|
|
UINT MoreHeaderInLookAhead = 0;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: \n"));
|
|
|
|
//
|
|
// 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 = net_short(IPH->iph_src);
|
|
Dst = net_short(IPH->iph_dest);
|
|
IPID = net_short(IPH->iph_id);
|
|
|
|
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 && !bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLockRecv);
|
|
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
|
|
if (IPID == IPIDListRecv[i]) {
|
|
|
|
if (bLastFragment) {
|
|
//
|
|
// If its the last fragment, release the slot.
|
|
//
|
|
IPIDListRecv[i] = 0xffff;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLockRecv);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldnt find an IPID that we care about, get outta here.\n"));
|
|
goto RECV_FAILURE;
|
|
|
|
}
|
|
//
|
|
// So we found a IPID that matches - set the timestamp and get out after this.
|
|
//
|
|
|
|
TotalLen = TotalIpLen - FragOffset;
|
|
pData = ((PUCHAR) IPH) + IpHdrLen;
|
|
|
|
if (TotalLen >= sizeof (LOG_RECORD)) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 RecdTime, Freq;
|
|
|
|
pRecord = (LOG_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;
|
|
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: *TCP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
|
|
IPH->iph_src,
|
|
IPH->iph_dest,
|
|
SrcPort,
|
|
DstPort));
|
|
|
|
TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
|
|
pData = (PUCHAR) TCPH + TcpHeaderOffset;
|
|
TcpDataLen = TotalTcpLen - TcpHeaderOffset;
|
|
|
|
if ((CheckInPortList(DstPort)) && (TcpDataLen > sizeof (LOG_RECORD))) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 RecdTime, Freq;
|
|
|
|
pRecord = (LOG_RECORD *) pData;
|
|
CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
|
|
|
|
//
|
|
// Convert the perffrequency into 100ns interval.
|
|
//
|
|
Freq = 0;
|
|
Freq |= PerfFrequency.HighPart;
|
|
Freq = Freq << 32;
|
|
Freq |= PerfFrequency.LowPart;
|
|
|
|
// convert 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;
|
|
|
|
|
|
//
|
|
//pRecord->TimeReceivedWire);
|
|
//
|
|
|
|
} else if (CheckInPortList(DstPort)) {
|
|
|
|
if (TcpDataLen < sizeof(LOG_RECORD))
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV,
|
|
("The Datagram was too small!! IpLen:%d, Tcplen:%d HeaderOff(tcp):%d log_record:%d\n", TotalIpLen, TotalTcpLen, TcpHeaderOffset, sizeof (LOG_RECORD)));
|
|
|
|
}
|
|
|
|
//
|
|
// If its the first fragment, keep a place holder so we know which
|
|
// subsequent IP fragments to timestamp.
|
|
//
|
|
if ((CheckInPortList(DstPort)) && bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLockRecv);
|
|
|
|
// need new Entry for IPID
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
//
|
|
// Look for a free slot
|
|
//
|
|
if (0xffff == IPIDListRecv[i]) {
|
|
|
|
IPIDListRecv[i] = IPID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLockRecv);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
TotalUdpLen = TotalIpLen - HeaderLength;
|
|
UDPH = (UDPHeader *) (((PUCHAR)IPH) + HeaderLength);
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("PAcket %x, IPH = %x, UDPH = %x, HeaderLength = %x\n", LookAheadBuffer, IPH, UDPH, HeaderLength));
|
|
|
|
UdpDataLen = TotalUdpLen - sizeof(UDPHeader);
|
|
pData = ((PUCHAR) UDPH) + sizeof (UDPHeader);
|
|
|
|
SrcPort = net_short(UDPH->uh_src); // Source port.
|
|
DstPort = net_short(UDPH->uh_dest); // Destination port.
|
|
|
|
if (UdpDataLen < sizeof(UDPHeader)) {
|
|
return TRUE;
|
|
}
|
|
|
|
if ((CheckInPortList(DstPort)) && (UdpDataLen > sizeof(LOG_RECORD))) {
|
|
|
|
LARGE_INTEGER PerfFrequency;
|
|
UINT64 RecdTime, Freq;
|
|
|
|
pRecord = (LOG_RECORD *) pData;
|
|
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;
|
|
|
|
|
|
//
|
|
// Dont want to get rejected due to bad xsum ...
|
|
//
|
|
UDPH->uh_xsum = 0;
|
|
|
|
} else if (CheckInPortList(DstPort)) {
|
|
|
|
if ((UdpDataLen) < sizeof(LOG_RECORD))
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("The Datagram was too small (UDP)!! IpLen:%d, Size:%d log_record:%d\n",
|
|
TotalIpLen, UdpDataLen, sizeof (LOG_RECORD)));
|
|
|
|
}
|
|
|
|
if ((CheckInPortList(DstPort)) && bFirstFragment) {
|
|
|
|
NdisAcquireSpinLock(&IPIDListLockRecv);
|
|
|
|
// need new Entry for IPID
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
//
|
|
// Look for a free slot
|
|
//
|
|
if (0xffff == IPIDListRecv[i]) {
|
|
|
|
IPIDListRecv[i] = IPID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&IPIDListLockRecv);
|
|
|
|
if (i == PORT_RANGE) {
|
|
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
|
|
}
|
|
}
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: *UDP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
|
|
IPH->iph_src,
|
|
IPH->iph_dest,
|
|
UDPH->uh_src,
|
|
UDPH->uh_dest));
|
|
|
|
break;
|
|
|
|
case IPPROTO_RAW:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol RAW\n"));
|
|
|
|
break;
|
|
|
|
case IPPROTO_IGMP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol IGMP\n"));
|
|
|
|
break;
|
|
|
|
case IPPROTO_ICMP:
|
|
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol TCMP\n"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol - UNKNOWN (%d)\n", IPH->iph_protocol));
|
|
|
|
//DbgBreakPoint();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RECV_FAILURE:
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
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;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_OID, ("[TimeStmpSetInformation]:\n"));
|
|
(*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;
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_OID, ("[TimeStmpQueryInformation]:\n"));
|
|
(*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
|
|
)
|
|
{
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_CLASS_MAP, ("[TimeStmpCreateClassMap]: \n"));
|
|
return (*PipeContext->NextComponent->CreateClassMap)(
|
|
PipeContext->NextComponentContext,
|
|
PsClassMapContext,
|
|
ClassMap,
|
|
ComponentClassMapContext->NextComponentContext);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
TimeStmpDeleteClassMap (
|
|
IN PPS_PIPE_CONTEXT PipeContext,
|
|
IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
|
|
)
|
|
{
|
|
TimeStmpTrace(TS_DBG_TRACE, TS_DBG_CLASS_MAP, ("[TimeStmpDeleteClassMap]: \n"));
|
|
return (*PipeContext->NextComponent->DeleteClassMap)(
|
|
PipeContext->NextComponentContext,
|
|
ComponentClassMapContext->NextComponentContext);
|
|
}
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
PSI_INFO Component;
|
|
NDIS_HANDLE ConfigHandle;
|
|
NDIS_STATUS Status;
|
|
NDIS_STRING ComponentKey = NDIS_STRING_CONST("DisplayName");
|
|
NDIS_STRING ComponentName = NDIS_STRING_CONST("TimeStmp");
|
|
PNDIS_CONFIGURATION_PARAMETER pConfigParam;
|
|
NDIS_STRING PsParamKey;
|
|
PWSTR p = RegistryPath->Buffer + RegistryPath->Length;
|
|
PS_DEBUG_INFO Dbg;
|
|
ULONG i = 0;
|
|
|
|
// The last word of Registry Path points to the driver name.
|
|
// NdisOpenProtocol needs that name!
|
|
while(p != RegistryPath->Buffer && *p != L'\\')
|
|
p-- ;
|
|
p++;
|
|
RtlInitUnicodeString(&PsParamKey, p);
|
|
DbgPrint("PsParamKey:%s\n", PsParamKey);
|
|
|
|
NdisOpenProtocolConfiguration(&Status, &ConfigHandle, &PsParamKey);
|
|
|
|
DbgPrint("Status of NdisOpenProtocol:%x\n", Status);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto failure;
|
|
}
|
|
|
|
//
|
|
// Check if psched is installed by opening it.
|
|
// If it fails, we dont load either.
|
|
//
|
|
Status = CheckForPsched();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
DbgPrint("PSCHED is NOT installed. Timestmp is bailing too\n");
|
|
goto failure;
|
|
}
|
|
|
|
IoctlInitialize(DriverObject);
|
|
|
|
// this list maintains a list of all ports that need to be timestamped.
|
|
InitializeListHead(&PortList);
|
|
NdisAllocateSpinLock(&PortSpinLock);
|
|
|
|
DriverObject->DriverUnload = TimeStmpUnload;
|
|
|
|
|
|
//
|
|
// We need to keep track of IPIDs for dealing with fragments
|
|
// that we need to stamp...
|
|
//
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
IPIDList[i] = 0xffff;
|
|
}
|
|
|
|
NdisAllocateSpinLock(&IPIDListLock);
|
|
|
|
//
|
|
// Do the same for the receive side.
|
|
//
|
|
for (i = 0; i < PORT_RANGE; i++) {
|
|
IPIDListRecv[i] = 0xffff;
|
|
}
|
|
|
|
NdisAllocateSpinLock(&IPIDListLockRecv);
|
|
|
|
|
|
if ( NT_SUCCESS( Status ))
|
|
{
|
|
// Read the name of the component from the registry
|
|
#if 0
|
|
NdisReadConfiguration( &Status,
|
|
&pConfigParam,
|
|
ConfigHandle,
|
|
&ComponentKey,
|
|
NdisParameterString);
|
|
if( NT_SUCCESS( Status ))
|
|
{
|
|
RtlInitUnicodeString(&Component.ComponentName,
|
|
pConfigParam->ParameterData.StringData.Buffer);
|
|
#else
|
|
RtlInitUnicodeString(&Component.ComponentName, ComponentName.Buffer);
|
|
#endif
|
|
|
|
Component.Version = PS_COMPONENT_CURRENT_VERSION;
|
|
Component.PacketReservedLength = 0;
|
|
Component.PipeContextLength = sizeof(PS_PIPE_CONTEXT);
|
|
Component.FlowContextLength = sizeof(PS_FLOW_CONTEXT);
|
|
Component.ClassMapContextLength = sizeof(PS_CLASS_MAP_CONTEXT);
|
|
Component.SupportedOidsLength = 0;
|
|
Component.SupportedOidList = 0;
|
|
Component.SupportedGuidsLength = 0;
|
|
Component.SupportedGuidList = 0;
|
|
Component.InitializePipe = TimeStmpInitializePipe;
|
|
Component.ModifyPipe = TimeStmpModifyPipe;
|
|
Component.DeletePipe = TimeStmpDeletePipe;
|
|
Component.CreateFlow = TimeStmpCreateFlow;
|
|
Component.ModifyFlow = TimeStmpModifyFlow;
|
|
Component.DeleteFlow = TimeStmpDeleteFlow;
|
|
Component.CreateClassMap = TimeStmpCreateClassMap;
|
|
Component.DeleteClassMap = TimeStmpDeleteClassMap;
|
|
Component.SubmitPacket = TimeStmpSubmitPacket;
|
|
Component.ReceivePacket = TimeStmpReceivePacket;
|
|
Component.ReceiveIndication = TimeStmpReceiveIndication;
|
|
Component.SetInformation = TimeStmpSetInformation;
|
|
Component.QueryInformation = TimeStmpQueryInformation;
|
|
|
|
//
|
|
// Call Psched's RegisterPsComponent
|
|
//
|
|
Status = RegisterPsComponent(&Component, sizeof(Component),
|
|
&Dbg);
|
|
if(Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
DbgPrint("Status of RegisterPsComponent%x\n", Status);
|
|
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_INIT,
|
|
("DriverEntry: RegisterPsComponent Failed \n"));
|
|
}
|
|
else
|
|
{
|
|
|
|
DbgPrint("Status of RegisterPsComponent:%x\n", Status);
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("Status of NdisReadProtocol:%x\n", Status);
|
|
|
|
DbgBreakPoint();
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_INIT,
|
|
("DriverEntry: ComponentName not specified \n"));
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
|
|
{
|
|
DbgPrint("Status of NdisOpenProtocol:%x\n", Status);
|
|
|
|
TimeStmpTrace(TS_DBG_DEATH, TS_DBG_INIT,
|
|
("DriverEntry: Can't read driver information in registry"
|
|
"\n"));
|
|
}
|
|
|
|
failure:
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// The following function checks for the existence of PSCHED on the machine.
|
|
// The assumption being that PSCHED gets loaded before TimeStmp on a system.
|
|
// If we can open the device, it means that PSCHED is on, otherwise, we bail.
|
|
// This fix is for Bug - 321618
|
|
//
|
|
NTSTATUS
|
|
CheckForPsched(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
OBJECT_ATTRIBUTES objectAttr;
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttr,
|
|
&PschedDriverName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = NtCreateFile(
|
|
&PschedHandle,
|
|
GENERIC_READ,
|
|
&objectAttr,
|
|
&ioStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0L);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
|
|
} else {
|
|
|
|
NtClose(PschedHandle);
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
PPORT_ENTRY
|
|
CheckInPortList(USHORT Port) {
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
PPORT_ENTRY pPortEntry;
|
|
|
|
NdisAcquireSpinLock(&PortSpinLock);
|
|
ListEntry = PortList.Flink;
|
|
|
|
while (ListEntry != &PortList) {
|
|
|
|
pPortEntry = CONTAINING_RECORD(ListEntry, PORT_ENTRY, Linkage);
|
|
if (Port == pPortEntry->Port) {
|
|
|
|
//DbgPrint("Found Port%d\n", Port);
|
|
NdisReleaseSpinLock(&PortSpinLock);
|
|
return pPortEntry;
|
|
|
|
} else {
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
//DbgPrint("NOT Found Trying NEXT\n");
|
|
}
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock(&PortSpinLock);
|
|
//DbgPrint("NOT Found returning from function\n");
|
|
return NULL;
|
|
}
|
|
|