/*++ Copyright (c) 1996-1999 Microsoft Corporation Module Name: timestmp.c Abstract: Timestamper module Author: Shreedhar Madhavapeddi (shreem) Revision History: --*/ #include // // 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; }