/*++ 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