Source code of Windows XP (NT5)
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
58 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. timestmp.c
  5. Abstract:
  6. Timestamper module
  7. Author:
  8. Shreedhar Madhavapeddi (shreem)
  9. Revision History:
  10. --*/
  11. #include <timestmp.h>
  12. //
  13. // The following struct has to be in ssync with
  14. // ndis\trfccntl\tools\qtcp\qtcp.c
  15. //
  16. typedef struct _LOG_RECORD{
  17. UINT64 TimeSent;
  18. UINT64 TimeReceived;
  19. UINT64 TimeSentWire; // These fields are used by the kernel timestamper
  20. UINT64 TimeReceivedWire; // These fields are used by the kernel timestamper
  21. UINT64 Latency;
  22. INT BufferSize;
  23. INT SequenceNumber;
  24. } LOG_RECORD, *PLOG_RECORD;
  25. ULONG GlobalSequenceNumber = 0;
  26. // 321618 needs checking for PSCHED's existence.
  27. NDIS_STRING PschedDriverName = NDIS_STRING_CONST("\\Device\\PSched");
  28. HANDLE PschedHandle;
  29. NTSTATUS CheckForPsched(VOID);
  30. //
  31. // TCP Headers (redefined here, since there are no exported headers
  32. //
  33. #define IP_OFFSET_MASK ~0x00E0 // Mask for extracting offset field.
  34. #define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
  35. /*
  36. * Protocols (from winsock.h)
  37. */
  38. #define IPPROTO_IP 0 /* dummy for IP */
  39. #define IPPROTO_ICMP 1 /* control message protocol */
  40. #define IPPROTO_IGMP 2 /* group management protocol */
  41. #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
  42. #define IPPROTO_TCP 6 /* tcp */
  43. #define IPPROTO_PUP 12 /* pup */
  44. #define IPPROTO_UDP 17 /* user datagram protocol */
  45. #define IPPROTO_IDP 22 /* xns idp */
  46. #define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
  47. #define IPPROTO_IPSEC 51 /* ???????? */
  48. #define IPPROTO_RAW 255 /* raw IP packet */
  49. #define IPPROTO_MAX 256
  50. #define IP_MF_FLAG 0x0020 // 'More fragments flag'
  51. #define IP_VERSION 0x40
  52. #define IP_VER_FLAG 0xF0
  53. #define TCP_OFFSET_MASK 0xf0
  54. #define TCP_HDR_SIZE(t) (uint)(((*(uchar *)&(t)->tcp_flags) & TCP_OFFSET_MASK) >> 2)
  55. typedef int SeqNum; // A sequence number.
  56. struct TCPHeader {
  57. ushort tcp_src; // Source port.
  58. ushort tcp_dest; // Destination port.
  59. SeqNum tcp_seq; // Sequence number.
  60. SeqNum tcp_ack; // Ack number.
  61. ushort tcp_flags; // Flags and data offset.
  62. ushort tcp_window; // Window offered.
  63. ushort tcp_xsum; // Checksum.
  64. ushort tcp_urgent; // Urgent pointer.
  65. };
  66. typedef struct TCPHeader TCPHeader;
  67. struct UDPHeader {
  68. ushort uh_src; // Source port.
  69. ushort uh_dest; // Destination port.
  70. ushort uh_length; // Length
  71. ushort uh_xsum; // Checksum.
  72. }; /* UDPHeader */
  73. typedef struct UDPHeader UDPHeader;
  74. #ifdef DBG
  75. //
  76. // Define the Trace Level.
  77. //
  78. #define TS_DBG_DEATH 1
  79. #define TS_DBG_TRACE 2
  80. //
  81. // Masks
  82. //
  83. #define TS_DBG_PIPE 0x00000001
  84. #define TS_DBG_FLOW 0x00000002
  85. #define TS_DBG_SEND 0x00000004
  86. #define TS_DBG_RECV 0x00000008
  87. #define TS_DBG_INIT 0x00000010
  88. #define TS_DBG_OID 0x00000020
  89. #define TS_DBG_CLASS_MAP 0x00000040
  90. ULONG DbgTraceLevel = 1;
  91. ULONG DbgTraceMask = 0x8;
  92. #define TimeStmpTrace(_DebugLevel, _DebugMask, _Out) \
  93. if ((DbgTraceLevel >= _DebugLevel) && \
  94. ((_DebugMask) & DbgTraceMask)){ \
  95. DbgPrint("TimeStamp: "); \
  96. DbgPrint _Out; \
  97. }
  98. #else // DBG
  99. #define TimeStmpTrace
  100. #endif
  101. #define PORT_RANGE 20
  102. USHORT IPIDList[PORT_RANGE];
  103. NDIS_SPIN_LOCK IPIDListLock;
  104. #define PORT_RANGE 20
  105. USHORT IPIDListRecv[PORT_RANGE];
  106. NDIS_SPIN_LOCK IPIDListLockRecv;
  107. /*
  108. Let's create a driver unload function, so that timestmp is stoppable via net sto
  109. p timestmp
  110. */
  111. VOID
  112. TimeStmpUnload(
  113. IN PDRIVER_OBJECT DriverObject
  114. )
  115. {
  116. IoctlCleanup();
  117. return;
  118. }
  119. NDIS_STATUS
  120. TimeStmpInitializePipe (
  121. IN HANDLE PsPipeContext,
  122. IN PPS_PIPE_PARAMETERS PipeParameters,
  123. IN PPS_PIPE_CONTEXT ComponentPipeContext,
  124. IN PPS_PROCS PsProcs,
  125. IN PPS_UPCALLS Upcalls
  126. )
  127. {
  128. PPS_PIPE_CONTEXT Pipe = ComponentPipeContext;
  129. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_PIPE, ("[TimeStmpIndicatePipe]: \n"));
  130. return (*Pipe->NextComponent->InitializePipe)(
  131. PsPipeContext,
  132. PipeParameters,
  133. Pipe->NextComponentContext,
  134. PsProcs,
  135. Upcalls);
  136. }
  137. NDIS_STATUS
  138. TimeStmpModifyPipe (
  139. IN PPS_PIPE_CONTEXT PipeContext,
  140. IN PPS_PIPE_PARAMETERS PipeParameters
  141. )
  142. {
  143. PPS_PIPE_CONTEXT Pipe = PipeContext;
  144. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_PIPE, ("[TimeStmpModifyPipe]: \n"));
  145. return (*Pipe->NextComponent->ModifyPipe)(
  146. Pipe->NextComponentContext, PipeParameters);
  147. }
  148. VOID
  149. TimeStmpDeletePipe (
  150. IN PPS_PIPE_CONTEXT PipeContext
  151. )
  152. {
  153. PPS_PIPE_CONTEXT Pipe = PipeContext;
  154. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_PIPE, ("[TimeStmpDeletePipe]: \n"));
  155. (*Pipe->NextComponent->DeletePipe)(Pipe->NextComponentContext);
  156. }
  157. NDIS_STATUS
  158. TimeStmpCreateFlow (
  159. IN PPS_PIPE_CONTEXT PipeContext,
  160. IN HANDLE PsFlowContext,
  161. IN PCO_CALL_PARAMETERS CallParameters,
  162. IN PPS_FLOW_CONTEXT ComponentFlowContext
  163. )
  164. {
  165. PPS_PIPE_CONTEXT Pipe = PipeContext;
  166. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_FLOW, ("[TimeStmpCreateFlow]: \n"));
  167. return (*Pipe->NextComponent->CreateFlow)(
  168. Pipe->NextComponentContext,
  169. PsFlowContext,
  170. CallParameters,
  171. ComponentFlowContext->NextComponentContext);
  172. }
  173. NDIS_STATUS
  174. TimeStmpModifyFlow (
  175. IN PPS_PIPE_CONTEXT PipeContext,
  176. IN PPS_FLOW_CONTEXT FlowContext,
  177. IN PCO_CALL_PARAMETERS CallParameters
  178. )
  179. {
  180. PPS_PIPE_CONTEXT Pipe = PipeContext;
  181. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_FLOW, ("[TimeStmpModifyFlow]: \n"));
  182. return (*Pipe->NextComponent->ModifyFlow)(
  183. Pipe->NextComponentContext,
  184. FlowContext->NextComponentContext,
  185. CallParameters);
  186. }
  187. VOID
  188. TimeStmpDeleteFlow (
  189. IN PPS_PIPE_CONTEXT PipeContext,
  190. IN PPS_FLOW_CONTEXT FlowContext
  191. )
  192. {
  193. PPS_PIPE_CONTEXT Pipe = PipeContext;
  194. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_FLOW, ("[TimeStmpDeleteFlow]: \n"));
  195. (*Pipe->NextComponent->DeleteFlow)(
  196. Pipe->NextComponentContext,
  197. FlowContext->NextComponentContext);
  198. }
  199. BOOLEAN
  200. TimeStmpSubmitPacket (
  201. IN PPS_PIPE_CONTEXT PipeContext,
  202. IN PPS_FLOW_CONTEXT FlowContext,
  203. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  204. IN PPACKET_INFO_BLOCK PacketInfo
  205. )
  206. {
  207. PPS_PIPE_CONTEXT Pipe = PipeContext;
  208. LARGE_INTEGER CurrentTime;
  209. IPHeader UNALIGNED *IPH = NULL;
  210. TCPHeader UNALIGNED *TCPH = NULL;
  211. UDPHeader UNALIGNED *UDPH = NULL;
  212. PVOID ArpH = NULL, GeneralVA = NULL, Data = NULL;
  213. IPAddr Src, Dst;
  214. PNDIS_BUFFER ArpBuf = NULL, IpBuf = NULL, TcpBuf = NULL, DataBuf = NULL, UdpBuf = NULL;
  215. ULONG ArpLen = 0, IpLen = 0, IpHdrLen = 0, TcpLen = 0, DataLen = 0, TotalLen = 0, TcpHeaderOffset = 0;
  216. ULONG UdpLen = 0;
  217. USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0;
  218. PLIST_ENTRY CurrentEntry = NULL, LastEntry = NULL;
  219. BOOLEAN bFragment, bFirstFragment, bLastFragment;
  220. ULONG i = 0;
  221. PLOG_RECORD pRecord = NULL;
  222. PNDIS_PACKET Packet = PacketInfo->NdisPacket;
  223. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: \n"));
  224. //
  225. // Steps
  226. // Parse the IP Packet.
  227. // Look for the appropriate ports.
  228. // Look for the data portion and put in the Time & length there.
  229. //
  230. NdisGetFirstBufferFromPacket(
  231. Packet,
  232. &ArpBuf,
  233. &ArpH,
  234. &ArpLen,
  235. &TotalLen
  236. );
  237. //
  238. // We are guaranteed that the ARP buffer if always a different MDL, so
  239. // jump to the next MDL
  240. //
  241. NdisGetNextBuffer(ArpBuf, &IpBuf)
  242. if (IpBuf) {
  243. NdisQueryBuffer(IpBuf,
  244. &GeneralVA,
  245. &IpLen
  246. );
  247. IPH = (IPHeader *) GeneralVA;
  248. if (!IPH) {
  249. goto FAILURE;
  250. }
  251. Src = net_short(IPH->iph_src);
  252. Dst = net_short(IPH->iph_dest);
  253. IPID = net_short(IPH->iph_id);
  254. //IpHdrLen = 8 * net_short(IPH->iph_length);
  255. IpHdrLen = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
  256. FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
  257. FragOffset = net_short(FragOffset) * 8;
  258. bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
  259. bFirstFragment = bFragment && (FragOffset == 0);
  260. bLastFragment = bFragment && (!(IPH->iph_offset & IP_MF_FLAG));
  261. if (bFragment && (!bFirstFragment)) {
  262. //
  263. // Its a fragment alright and NOT the first one.
  264. //
  265. NdisAcquireSpinLock(&IPIDListLock);
  266. for (i = 0; i < PORT_RANGE; i++) {
  267. //
  268. // Found the match...
  269. //
  270. if (IPIDList[i] == IPID) {
  271. if (bLastFragment) {
  272. //
  273. // Since it is the last fragment, recall
  274. // the IP ID.
  275. //
  276. IPIDList[i] = 0xffff;
  277. }
  278. NdisReleaseSpinLock(&IPIDListLock);
  279. //
  280. // Is the data in the same buffer?
  281. //
  282. if (IpLen <= IpHdrLen) {
  283. NdisGetNextBuffer(IpBuf, &DataBuf);
  284. if(DataBuf) {
  285. NdisQueryBuffer(DataBuf,
  286. &Data,
  287. &DataLen
  288. );
  289. goto TimeStamp;
  290. } else {
  291. goto FAILURE;
  292. }
  293. } else {
  294. //
  295. // The Data Offsets need to be primed now.
  296. //
  297. DataLen = IpLen - FragOffset;
  298. Data = ((PUCHAR) GeneralVA) + IpHdrLen;
  299. goto TimeStamp;
  300. }
  301. }
  302. }
  303. NdisReleaseSpinLock(&IPIDListLock);
  304. //
  305. // If we are here, we dont care about this IPID for this fragment.
  306. // Just return TRUE to continue processing.
  307. //
  308. //
  309. // Ready to go.
  310. //
  311. PacketInfo->FlowContext = FlowContext;
  312. PacketInfo->ClassMapContext = ClassMapContext;
  313. return (*Pipe->NextComponent->SubmitPacket)(
  314. Pipe->NextComponentContext,
  315. FlowContext->NextComponentContext,
  316. ClassMapContext?ClassMapContext->NextComponentContext:0,
  317. PacketInfo);
  318. }
  319. //
  320. // If it is not a fragment, depending upon the protocol, process differently
  321. //
  322. switch (IPH->iph_protocol) {
  323. case IPPROTO_TCP :
  324. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Procol TCP\n"));
  325. if (IPH && ((USHORT)IpLen > IpHdrLen)) {
  326. //
  327. // We have more than the IP Header in this MDL.
  328. //
  329. TCPH = (TCPHeader *) ((PUCHAR)GeneralVA + IpHdrLen);
  330. TcpLen = IpLen - IpHdrLen;
  331. TcpBuf = IpBuf;
  332. } else {
  333. //
  334. // TCP Header is in the next MDL
  335. //
  336. NdisGetNextBuffer(IpBuf, &TcpBuf);
  337. if(TcpBuf) {
  338. GeneralVA = NULL;
  339. NdisQueryBuffer(TcpBuf,
  340. &GeneralVA,
  341. &TcpLen
  342. );
  343. TCPH = (TCPHeader *) GeneralVA;
  344. } else {
  345. goto FAILURE;
  346. }
  347. }
  348. //
  349. // Get the port numbers out.
  350. //
  351. SrcPort = net_short(TCPH->tcp_src);
  352. DstPort = net_short(TCPH->tcp_dest);
  353. //
  354. // We have the TCP Buffer now. Get to the DATA.
  355. //
  356. TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
  357. if (TcpLen > TcpHeaderOffset) {
  358. //
  359. // We have the DATA right here!
  360. //
  361. Data = (PUCHAR)TCPH + TcpHeaderOffset;
  362. DataLen = TcpLen - TcpHeaderOffset;
  363. } else {
  364. NdisGetNextBuffer(TcpBuf, &DataBuf);
  365. if(DataBuf) {
  366. GeneralVA = NULL;
  367. NdisQueryBuffer(DataBuf,
  368. &Data,
  369. &DataLen
  370. );
  371. } else {
  372. goto FAILURE;
  373. }
  374. }
  375. if (CheckInPortList(DstPort) && bFirstFragment) {
  376. NdisAcquireSpinLock(&IPIDListLock);
  377. // need new Entry for IPID
  378. for (i = 0; i < PORT_RANGE; i++) {
  379. //
  380. // Look for a free slot
  381. //
  382. if (0xffff == IPIDList[i]) {
  383. IPIDList[i] = IPID;
  384. break;
  385. }
  386. }
  387. NdisReleaseSpinLock(&IPIDListLock);
  388. if (i == PORT_RANGE) {
  389. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_SEND, ("Couldn't find an empty IPID - Bailing \n"));
  390. goto FAILURE;
  391. }
  392. //DbgBreakPoint();
  393. }
  394. //
  395. // Let's timestmp this now.
  396. //
  397. if (CheckInPortList(DstPort)) {
  398. goto TimeStamp;
  399. } else {
  400. //
  401. // This is not one of our packet, get out.
  402. //
  403. goto FAILURE;
  404. }
  405. break;
  406. case IPPROTO_UDP:
  407. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol UDP\n"));
  408. if (IPH && (IpLen > IpHdrLen)) {
  409. //
  410. // We have more than the IP Header in this MDL.
  411. //
  412. UDPH = (UDPHeader *) ((PUCHAR)GeneralVA + IpHdrLen);
  413. UdpLen = IpLen - IpHdrLen;
  414. UdpBuf = IpBuf;
  415. } else {
  416. //
  417. // UDP Header is in the next MDL
  418. //
  419. NdisGetNextBuffer(IpBuf, &UdpBuf);
  420. if(UdpBuf) {
  421. GeneralVA = NULL;
  422. NdisQueryBuffer(UdpBuf,
  423. &GeneralVA,
  424. &UdpLen
  425. );
  426. UDPH = (UDPHeader *) GeneralVA;
  427. } else {
  428. goto FAILURE;
  429. }
  430. }
  431. SrcPort = net_short(UDPH->uh_src); // Source port.
  432. DstPort = net_short(UDPH->uh_dest); // Destination port.
  433. //
  434. // Get to the data.
  435. //
  436. if (UdpLen > sizeof (UDPHeader)) {
  437. //
  438. // We have the DATA right here!
  439. //
  440. Data = (PUCHAR) UDPH + sizeof (UDPHeader);
  441. DataLen = UdpLen - sizeof (UDPHeader);
  442. } else {
  443. NdisGetNextBuffer(UdpBuf, &DataBuf);
  444. if(DataBuf) {
  445. GeneralVA = NULL;
  446. NdisQueryBuffer(DataBuf,
  447. &Data,
  448. &DataLen
  449. );
  450. } else {
  451. goto FAILURE;
  452. }
  453. }
  454. if (CheckInPortList(DstPort) && bFirstFragment) {
  455. NdisAcquireSpinLock(&IPIDListLock);
  456. // need new Entry for IPID
  457. for (i = 0; i < PORT_RANGE; i++) {
  458. //
  459. // Look for a free slot
  460. //
  461. if (0xffff == IPIDList[i]) {
  462. IPIDList[i] = IPID;
  463. break;
  464. }
  465. ASSERT(FALSE);
  466. }
  467. NdisReleaseSpinLock(&IPIDListLock);
  468. //
  469. // Couldnt find a free IPID place holder, lets bail.
  470. //
  471. if (PORT_RANGE == i) {
  472. goto FAILURE;
  473. }
  474. }
  475. //
  476. // Let's timestmp this now.
  477. //
  478. if (CheckInPortList(DstPort)) {
  479. goto TimeStamp;
  480. } else {
  481. //
  482. // This is not one of our packet, get out.
  483. //
  484. goto FAILURE;
  485. }
  486. break;
  487. case IPPROTO_RAW:
  488. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol RAW\n"));
  489. goto FAILURE;
  490. break;
  491. case IPPROTO_IGMP:
  492. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol IGMP\n"));
  493. goto FAILURE;
  494. break;
  495. case IPPROTO_ICMP:
  496. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol TCMP\n"));
  497. goto FAILURE;
  498. break;
  499. default:
  500. //TimeStmpTrace(TS_DBG_DEATH, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: Protocol - UNKNOWN (%d)\n", IPH->iph_protocol));
  501. goto FAILURE;
  502. //DbgBreakPoint();
  503. }
  504. } else {
  505. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_SEND, ("[TimeStmpSubmitPacket]: NO Buffer beyond MAC Header\n"));
  506. goto FAILURE;
  507. }
  508. TimeStamp:
  509. //
  510. // If we get here, the Data and DataLen variables have been primed.
  511. // Set the Time and Length.
  512. //
  513. if (Data) {
  514. pRecord = (PLOG_RECORD) Data;
  515. if (DataLen > sizeof (LOG_RECORD)) {
  516. LARGE_INTEGER PerfFrequency;
  517. UINT64 Freq;
  518. //
  519. // Set the fields accordingly
  520. pRecord->BufferSize = DataLen;
  521. //pRecord->SequenceNumber = InterlockedIncrement(&GlobalSequenceNumber);
  522. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  523. //
  524. // Convert the perffrequency into 100ns interval.
  525. //
  526. Freq = 0;
  527. Freq |= PerfFrequency.HighPart;
  528. Freq = Freq << 32;
  529. Freq |= PerfFrequency.LowPart;
  530. //
  531. // Convert from LARGE_INTEGER to UINT64
  532. //
  533. pRecord->TimeSentWire = 0;
  534. pRecord->TimeSentWire |= CurrentTime.HighPart;
  535. pRecord->TimeSentWire = pRecord->TimeSentWire << 32;
  536. pRecord->TimeSentWire |= CurrentTime.LowPart;
  537. // Normalize cycles with the frequency.
  538. pRecord->TimeSentWire *= 10000000;
  539. pRecord->TimeSentWire /= Freq;
  540. }
  541. }
  542. //
  543. // Ready to go.
  544. //
  545. PacketInfo->FlowContext = FlowContext;
  546. PacketInfo->ClassMapContext = ClassMapContext;
  547. return (*Pipe->NextComponent->SubmitPacket)(
  548. Pipe->NextComponentContext,
  549. FlowContext->NextComponentContext,
  550. ClassMapContext?ClassMapContext->NextComponentContext:0,
  551. PacketInfo);
  552. FAILURE:
  553. //
  554. // Ready to go.
  555. //
  556. PacketInfo->FlowContext = FlowContext;
  557. PacketInfo->ClassMapContext = ClassMapContext;
  558. return (*Pipe->NextComponent->SubmitPacket)(
  559. Pipe->NextComponentContext,
  560. FlowContext->NextComponentContext,
  561. ClassMapContext?ClassMapContext->NextComponentContext:0,
  562. PacketInfo);
  563. }
  564. BOOLEAN
  565. TimeStmpReceivePacket (
  566. IN PPS_PIPE_CONTEXT PipeContext,
  567. IN PPS_FLOW_CONTEXT FlowContext,
  568. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  569. IN PNDIS_PACKET Packet,
  570. IN NDIS_MEDIUM Medium
  571. )
  572. {
  573. PPS_PIPE_CONTEXT Pipe = PipeContext;
  574. LARGE_INTEGER CurrentTime;
  575. IPHeader UNALIGNED *IPH = NULL;
  576. TCPHeader UNALIGNED *TCPH = NULL;
  577. UDPHeader UNALIGNED *UDPH = NULL;
  578. IPAddr Src, Dst;
  579. PUCHAR headerBuffer = NULL, pData = NULL;
  580. PNDIS_BUFFER pFirstBuffer = NULL;
  581. ULONG firstbufferLength = 0, bufferLength = 0, HeaderLength = 0;
  582. ULONG TotalIpLen = 0, IPDataLength = 0, IpHdrLen = 0;
  583. ULONG TotalTcpLen = 0, TcpDataLen = 0, TotalLen = 0, TcpHeaderOffset = 0, Size = 0;
  584. ULONG TotalUdpLen = 0, UdpDataLen = 0, UdpHdrLen = 0;
  585. USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0;
  586. BOOLEAN bFragment, bFirstFragment, bLastFragment;
  587. ULONG i = 0;
  588. PLOG_RECORD pRecord = NULL;
  589. UINT HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
  590. ushort type; // Protocol type
  591. uint ProtOffset; // Offset in Data to non-media info.
  592. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: \n"));
  593. NdisGetFirstBufferFromPacket(Packet, // packet
  594. &pFirstBuffer, // first buffer descriptor
  595. &headerBuffer, // ptr to the start of packet
  596. &firstbufferLength, // length of the header+lookahead
  597. &bufferLength); // length of the bytes in the buffers
  598. IPH = (IPHeader *) ((PUCHAR)headerBuffer + HeaderBufferSize);
  599. // Check the header length and the version. If any of these
  600. // checks fail silently discard the packet.
  601. HeaderLength = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
  602. if (HeaderLength >= sizeof(IPHeader) && HeaderLength <= bufferLength) {
  603. //
  604. // Get past the IP Header and get the rest of the stuff out.
  605. //
  606. TotalIpLen = (uint)net_short(IPH->iph_length);
  607. if ((IPH->iph_verlen & IP_VER_FLAG) == IP_VERSION &&
  608. TotalIpLen >= HeaderLength && TotalIpLen <= bufferLength) {
  609. Src = net_short(IPH->iph_src);
  610. Dst = net_short(IPH->iph_dest);
  611. IPID = net_short(IPH->iph_id);
  612. FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
  613. FragOffset = net_short(FragOffset) * 8;
  614. bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
  615. bFirstFragment = bFragment && (FragOffset == 0);
  616. bLastFragment = bFragment && (!(IPH->iph_offset & IP_MF_FLAG));
  617. //
  618. // If this is a fragment and NOT the first one, just put the Timestamp in here.
  619. // Otherwise, let it get to the protocols for processing.
  620. //
  621. if (bFragment && !bFirstFragment) {
  622. NdisAcquireSpinLock(&IPIDListLockRecv);
  623. for (i = 0; i < PORT_RANGE; i++) {
  624. if (IPID == IPIDListRecv[i]) {
  625. if (bLastFragment) {
  626. //
  627. // If its the last fragment, release the slot.
  628. //
  629. IPIDListRecv[i] = 0xffff;
  630. }
  631. break;
  632. }
  633. }
  634. NdisReleaseSpinLock(&IPIDListLockRecv);
  635. if (i == PORT_RANGE) {
  636. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldnt find an IPID that we care about, get outta here.\n"));
  637. goto RECV_FAILURE;
  638. }
  639. //
  640. // So we found a IPID that matches - set the timestamp and get out after this.
  641. //
  642. TotalLen = TotalIpLen - FragOffset;
  643. pData = ((PUCHAR) IPH) + IpHdrLen;
  644. if (TotalLen > sizeof (LOG_RECORD)) {
  645. LARGE_INTEGER PerfFrequency;
  646. UINT64 RecdTime, Freq;
  647. pRecord = (LOG_RECORD *) pData;
  648. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  649. //
  650. // Convert the perffrequency into 100ns interval.
  651. //
  652. Freq = 0;
  653. Freq |= PerfFrequency.HighPart;
  654. Freq = Freq << 32;
  655. Freq |= PerfFrequency.LowPart;
  656. //convert from Largeinteger to uint64
  657. pRecord->TimeReceivedWire = 0;
  658. pRecord->TimeReceivedWire |= CurrentTime.HighPart;
  659. pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
  660. pRecord->TimeReceivedWire |= CurrentTime.LowPart;
  661. // Normalize cycles with the frequency.
  662. pRecord->TimeReceivedWire *= 10000000;
  663. pRecord->TimeReceivedWire /= Freq;
  664. }
  665. return TRUE;
  666. }
  667. //
  668. // Do the protocol specific stuff.
  669. //
  670. switch (IPH->iph_protocol) {
  671. case IPPROTO_TCP:
  672. TotalTcpLen = TotalIpLen - HeaderLength;
  673. TCPH = (TCPHeader *) (((PUCHAR)IPH) + HeaderLength);
  674. SrcPort = net_short(TCPH->tcp_src);
  675. DstPort = net_short(TCPH->tcp_dest);
  676. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: *TCP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
  677. IPH->iph_src,
  678. IPH->iph_dest,
  679. SrcPort,
  680. DstPort));
  681. TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
  682. pData = (PUCHAR) TCPH + TcpHeaderOffset;
  683. TcpDataLen = TotalTcpLen - TcpHeaderOffset;
  684. if ((CheckInPortList(DstPort)) && (TcpDataLen > sizeof (LOG_RECORD))) {
  685. LARGE_INTEGER PerfFrequency;
  686. UINT64 RecdTime, Freq;
  687. pRecord = (LOG_RECORD *) pData;
  688. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  689. //
  690. // Convert the perffrequency into 100ns interval.
  691. //
  692. Freq = 0;
  693. Freq |= PerfFrequency.HighPart;
  694. Freq = Freq << 32;
  695. Freq |= PerfFrequency.LowPart;
  696. //convert from large_integer to uint64
  697. pRecord->TimeReceivedWire = 0;
  698. pRecord->TimeReceivedWire |= CurrentTime.HighPart;
  699. pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
  700. pRecord->TimeReceivedWire |= CurrentTime.LowPart;
  701. // Normalize cycles with the frequency.
  702. pRecord->TimeReceivedWire *= 10000000;
  703. pRecord->TimeReceivedWire /= Freq;
  704. } else if (CheckInPortList(DstPort)) {
  705. if (TcpDataLen < sizeof(LOG_RECORD))
  706. 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)));
  707. }
  708. //
  709. // If its the first fragment, keep a place holder so we know which
  710. // subsequent IP fragments to timestamp.
  711. //
  712. if ((CheckInPortList(DstPort)) && bFirstFragment) {
  713. NdisAcquireSpinLock(&IPIDListLockRecv);
  714. // need new Entry for IPID
  715. for (i = 0; i < PORT_RANGE; i++) {
  716. //
  717. // Look for a free slot
  718. //
  719. if (0xffff == IPIDListRecv[i]) {
  720. IPIDListRecv[i] = IPID;
  721. break;
  722. }
  723. }
  724. NdisReleaseSpinLock(&IPIDListLockRecv);
  725. if (i == PORT_RANGE) {
  726. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
  727. }
  728. }
  729. break;
  730. case IPPROTO_UDP:
  731. TotalUdpLen = TotalIpLen - HeaderLength;
  732. UDPH = (UDPHeader *) (((PUCHAR)IPH) + HeaderLength);
  733. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("PAcket %x, IPH = %x, UDPH = %x, HeaderLength = %x\n", Packet, IPH, UDPH, HeaderLength));
  734. UdpDataLen = TotalUdpLen - sizeof(UDPHeader);
  735. pData = ((PUCHAR) UDPH) + sizeof (UDPHeader);
  736. SrcPort = net_short(UDPH->uh_src); // Source port.
  737. DstPort = net_short(UDPH->uh_dest); // Destination port.
  738. if (UdpDataLen < sizeof(UDPHeader)) {
  739. return TRUE;
  740. }
  741. if ((CheckInPortList(DstPort)) && (UdpDataLen > sizeof(LOG_RECORD))) {
  742. LARGE_INTEGER PerfFrequency;
  743. UINT64 RecdTime, Freq;
  744. pRecord = (LOG_RECORD *) pData;
  745. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  746. //
  747. // Convert the perffrequency into 100ns interval.
  748. //
  749. Freq = 0;
  750. Freq |= PerfFrequency.HighPart;
  751. Freq = Freq << 32;
  752. Freq |= PerfFrequency.LowPart;
  753. // convert to uint64
  754. pRecord->TimeReceivedWire = 0;
  755. pRecord->TimeReceivedWire |= CurrentTime.HighPart;
  756. pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
  757. pRecord->TimeReceivedWire |= CurrentTime.LowPart;
  758. // Normalize cycles with the frequency.
  759. pRecord->TimeReceivedWire *= 10000000;
  760. pRecord->TimeReceivedWire /= Freq;
  761. //
  762. // Dont want to get rejected due to bad xsum ...
  763. //
  764. UDPH->uh_xsum = 0;
  765. } else if (CheckInPortList(DstPort)) {
  766. if ((UdpDataLen) < sizeof(LOG_RECORD))
  767. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("The Datagram was too small (UDP)!! IpLen:%d, Size:%d log_record:%d\n",
  768. TotalIpLen, UdpDataLen, sizeof (LOG_RECORD)));
  769. }
  770. if ((CheckInPortList(DstPort)) && bFirstFragment) {
  771. NdisAcquireSpinLock(&IPIDListLockRecv);
  772. // need new Entry for IPID
  773. for (i = 0; i < PORT_RANGE; i++) {
  774. //
  775. // Look for a free slot
  776. //
  777. if (0xffff == IPIDListRecv[i]) {
  778. IPIDListRecv[i] = IPID;
  779. break;
  780. }
  781. }
  782. NdisReleaseSpinLock(&IPIDListLockRecv);
  783. if (i == PORT_RANGE) {
  784. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
  785. }
  786. }
  787. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: *UDP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
  788. IPH->iph_src,
  789. IPH->iph_dest,
  790. UDPH->uh_src,
  791. UDPH->uh_dest));
  792. break;
  793. case IPPROTO_RAW:
  794. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol RAW\n"));
  795. break;
  796. case IPPROTO_IGMP:
  797. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol IGMP\n"));
  798. break;
  799. case IPPROTO_ICMP:
  800. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol TCMP\n"));
  801. break;
  802. default:
  803. ;
  804. //TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("[TimeStmpReceivePacket]: Protocol - UNKNOWN (%d)\n", IPH->iph_protocol));
  805. //DbgBreakPoint();
  806. }
  807. }
  808. }
  809. RECV_FAILURE:
  810. return TRUE;
  811. }
  812. //
  813. // This function receives a buffer from NDIS which is indicated to the transport.
  814. // We use this function and work past the headers (tcp, ip) and get to the data.
  815. // Then, we timestamp and reset the checksum flags.
  816. // We make the assumption that the lookahead is atleast 128.
  817. // mac header ~ 8+8, ip header ~20, tcp/udp ~ 20+options, LOG_RECORD ~ 44
  818. // they all add up to less than 128. If this is not a good assumption, We will need
  819. // to get into MiniportTransferData and such.
  820. //
  821. BOOLEAN
  822. TimeStmpReceiveIndication(
  823. IN PPS_PIPE_CONTEXT PipeContext,
  824. IN PPS_FLOW_CONTEXT FlowContext,
  825. IN PPS_CLASS_MAP_CONTEXT ClassMapContext,
  826. IN PVOID HeaderBuffer,
  827. IN UINT HeaderBufferSize,
  828. IN PVOID LookAheadBuffer,
  829. IN UINT LookAheadBufferSize,
  830. IN UINT PacketSize,
  831. IN UINT TransportHeaderOffset
  832. )
  833. {
  834. PPS_PIPE_CONTEXT Pipe = PipeContext;
  835. LARGE_INTEGER CurrentTime;
  836. IPHeader UNALIGNED *IPH = NULL;
  837. TCPHeader UNALIGNED *TCPH = NULL;
  838. UDPHeader UNALIGNED *UDPH = NULL;
  839. IPAddr Src, Dst;
  840. PUCHAR headerBuffer = NULL, pData = NULL;
  841. PNDIS_BUFFER pFirstBuffer = NULL;
  842. ULONG firstbufferLength = 0, bufferLength = 0, HeaderLength = 0;
  843. ULONG TotalIpLen = 0, IPDataLength = 0, IpHdrLen = 0;
  844. ULONG TotalTcpLen = 0, TcpDataLen = 0, TotalLen = 0, TcpHeaderOffset = 0, Size = 0;
  845. ULONG TotalUdpLen = 0, UdpDataLen = 0, UdpHdrLen = 0;
  846. USHORT SrcPort = 0, DstPort = 0, IPID = 0, FragOffset = 0;
  847. BOOLEAN bFragment, bFirstFragment, bLastFragment;
  848. ULONG i = 0;
  849. PLOG_RECORD pRecord = NULL;
  850. ushort type; // Protocol type
  851. uint ProtOffset; // Offset in Data to non-media info.
  852. UINT MoreHeaderInLookAhead = 0;
  853. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: \n"));
  854. //
  855. // Don't know anything about the MAC headers, piggy back from PSCHED...
  856. // Calculate if the header is more than the standard HeaderBufferSize (i.e. SNAP header, etc.)
  857. //
  858. MoreHeaderInLookAhead = TransportHeaderOffset - HeaderBufferSize;
  859. if (MoreHeaderInLookAhead) {
  860. //
  861. // Just munge these, so that we can actually get down to business.
  862. //
  863. ((PUCHAR) LookAheadBuffer) += MoreHeaderInLookAhead;
  864. LookAheadBufferSize -= MoreHeaderInLookAhead;
  865. }
  866. if (LookAheadBufferSize > sizeof(IPHeader)) {
  867. IPH = (IPHeader *) (PUCHAR)LookAheadBuffer;
  868. // Check the header length and the version. If any of these
  869. // checks fail silently discard the packet.
  870. HeaderLength = ((IPH->iph_verlen & (uchar)~IP_VER_FLAG) << 2);
  871. if (HeaderLength >= sizeof(IPHeader) && HeaderLength <= LookAheadBufferSize) {
  872. //
  873. // Get past the IP Header and get the rest of the stuff out.
  874. //
  875. TotalIpLen = (uint)net_short(IPH->iph_length);
  876. if ((IPH->iph_verlen & IP_VER_FLAG) == IP_VERSION &&
  877. TotalIpLen >= HeaderLength && TotalIpLen <= LookAheadBufferSize) {
  878. Src = net_short(IPH->iph_src);
  879. Dst = net_short(IPH->iph_dest);
  880. IPID = net_short(IPH->iph_id);
  881. FragOffset = IPH->iph_offset & IP_OFFSET_MASK;
  882. FragOffset = net_short(FragOffset) * 8;
  883. bFragment = (IPH->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
  884. bFirstFragment = bFragment && (FragOffset == 0);
  885. bLastFragment = bFragment && (!(IPH->iph_offset & IP_MF_FLAG));
  886. //
  887. // If this is a fragment and NOT the first one, just put the Timestamp in here.
  888. // Otherwise, let it get to the protocols for processing.
  889. //
  890. if (bFragment && !bFirstFragment) {
  891. NdisAcquireSpinLock(&IPIDListLockRecv);
  892. for (i = 0; i < PORT_RANGE; i++) {
  893. if (IPID == IPIDListRecv[i]) {
  894. if (bLastFragment) {
  895. //
  896. // If its the last fragment, release the slot.
  897. //
  898. IPIDListRecv[i] = 0xffff;
  899. }
  900. break;
  901. }
  902. }
  903. NdisReleaseSpinLock(&IPIDListLockRecv);
  904. if (i == PORT_RANGE) {
  905. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldnt find an IPID that we care about, get outta here.\n"));
  906. goto RECV_FAILURE;
  907. }
  908. //
  909. // So we found a IPID that matches - set the timestamp and get out after this.
  910. //
  911. TotalLen = TotalIpLen - FragOffset;
  912. pData = ((PUCHAR) IPH) + IpHdrLen;
  913. if (TotalLen >= sizeof (LOG_RECORD)) {
  914. LARGE_INTEGER PerfFrequency;
  915. UINT64 RecdTime, Freq;
  916. pRecord = (LOG_RECORD *) pData;
  917. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  918. //
  919. // Convert the perffrequency into 100ns interval.
  920. //
  921. Freq = 0;
  922. Freq |= PerfFrequency.HighPart;
  923. Freq = Freq << 32;
  924. Freq |= PerfFrequency.LowPart;
  925. //
  926. // Convert from LARGE_INTEGER to UINT64
  927. //
  928. pRecord->TimeReceivedWire = 0;
  929. pRecord->TimeReceivedWire |= CurrentTime.HighPart;
  930. pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
  931. pRecord->TimeReceivedWire |= CurrentTime.LowPart;
  932. // Normalize cycles with the frequency.
  933. pRecord->TimeReceivedWire *= 10000000;
  934. pRecord->TimeReceivedWire /= Freq;
  935. }
  936. return TRUE;
  937. }
  938. //
  939. // Do the protocol specific stuff.
  940. //
  941. switch (IPH->iph_protocol) {
  942. case IPPROTO_TCP:
  943. TotalTcpLen = TotalIpLen - HeaderLength;
  944. TCPH = (TCPHeader *) (((PUCHAR)IPH) + HeaderLength);
  945. SrcPort = net_short(TCPH->tcp_src);
  946. DstPort = net_short(TCPH->tcp_dest);
  947. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: *TCP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
  948. IPH->iph_src,
  949. IPH->iph_dest,
  950. SrcPort,
  951. DstPort));
  952. TcpHeaderOffset = TCP_HDR_SIZE(TCPH);
  953. pData = (PUCHAR) TCPH + TcpHeaderOffset;
  954. TcpDataLen = TotalTcpLen - TcpHeaderOffset;
  955. if ((CheckInPortList(DstPort)) && (TcpDataLen > sizeof (LOG_RECORD))) {
  956. LARGE_INTEGER PerfFrequency;
  957. UINT64 RecdTime, Freq;
  958. pRecord = (LOG_RECORD *) pData;
  959. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  960. //
  961. // Convert the perffrequency into 100ns interval.
  962. //
  963. Freq = 0;
  964. Freq |= PerfFrequency.HighPart;
  965. Freq = Freq << 32;
  966. Freq |= PerfFrequency.LowPart;
  967. // convert to uint64
  968. pRecord->TimeReceivedWire = 0;
  969. pRecord->TimeReceivedWire |= CurrentTime.HighPart;
  970. pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
  971. pRecord->TimeReceivedWire |= CurrentTime.LowPart;
  972. // Normalize cycles with the frequency.
  973. pRecord->TimeReceivedWire *= 10000000;
  974. pRecord->TimeReceivedWire /= Freq;
  975. //
  976. //pRecord->TimeReceivedWire);
  977. //
  978. } else if (CheckInPortList(DstPort)) {
  979. if (TcpDataLen < sizeof(LOG_RECORD))
  980. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV,
  981. ("The Datagram was too small!! IpLen:%d, Tcplen:%d HeaderOff(tcp):%d log_record:%d\n", TotalIpLen, TotalTcpLen, TcpHeaderOffset, sizeof (LOG_RECORD)));
  982. }
  983. //
  984. // If its the first fragment, keep a place holder so we know which
  985. // subsequent IP fragments to timestamp.
  986. //
  987. if ((CheckInPortList(DstPort)) && bFirstFragment) {
  988. NdisAcquireSpinLock(&IPIDListLockRecv);
  989. // need new Entry for IPID
  990. for (i = 0; i < PORT_RANGE; i++) {
  991. //
  992. // Look for a free slot
  993. //
  994. if (0xffff == IPIDListRecv[i]) {
  995. IPIDListRecv[i] = IPID;
  996. break;
  997. }
  998. }
  999. NdisReleaseSpinLock(&IPIDListLockRecv);
  1000. if (i == PORT_RANGE) {
  1001. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
  1002. }
  1003. }
  1004. break;
  1005. case IPPROTO_UDP:
  1006. TotalUdpLen = TotalIpLen - HeaderLength;
  1007. UDPH = (UDPHeader *) (((PUCHAR)IPH) + HeaderLength);
  1008. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("PAcket %x, IPH = %x, UDPH = %x, HeaderLength = %x\n", LookAheadBuffer, IPH, UDPH, HeaderLength));
  1009. UdpDataLen = TotalUdpLen - sizeof(UDPHeader);
  1010. pData = ((PUCHAR) UDPH) + sizeof (UDPHeader);
  1011. SrcPort = net_short(UDPH->uh_src); // Source port.
  1012. DstPort = net_short(UDPH->uh_dest); // Destination port.
  1013. if (UdpDataLen < sizeof(UDPHeader)) {
  1014. return TRUE;
  1015. }
  1016. if ((CheckInPortList(DstPort)) && (UdpDataLen > sizeof(LOG_RECORD))) {
  1017. LARGE_INTEGER PerfFrequency;
  1018. UINT64 RecdTime, Freq;
  1019. pRecord = (LOG_RECORD *) pData;
  1020. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  1021. //
  1022. // Convert the perffrequency into 100ns interval.
  1023. //
  1024. Freq = 0;
  1025. Freq |= PerfFrequency.HighPart;
  1026. Freq = Freq << 32;
  1027. Freq |= PerfFrequency.LowPart;
  1028. pRecord->TimeReceivedWire = 0;
  1029. pRecord->TimeReceivedWire |= CurrentTime.HighPart;
  1030. pRecord->TimeReceivedWire = pRecord->TimeReceivedWire << 32;
  1031. pRecord->TimeReceivedWire |= CurrentTime.LowPart;
  1032. // Normalize cycles with the frequency.
  1033. pRecord->TimeReceivedWire *= 10000000;
  1034. pRecord->TimeReceivedWire /= Freq;
  1035. //
  1036. // Dont want to get rejected due to bad xsum ...
  1037. //
  1038. UDPH->uh_xsum = 0;
  1039. } else if (CheckInPortList(DstPort)) {
  1040. if ((UdpDataLen) < sizeof(LOG_RECORD))
  1041. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("The Datagram was too small (UDP)!! IpLen:%d, Size:%d log_record:%d\n",
  1042. TotalIpLen, UdpDataLen, sizeof (LOG_RECORD)));
  1043. }
  1044. if ((CheckInPortList(DstPort)) && bFirstFragment) {
  1045. NdisAcquireSpinLock(&IPIDListLockRecv);
  1046. // need new Entry for IPID
  1047. for (i = 0; i < PORT_RANGE; i++) {
  1048. //
  1049. // Look for a free slot
  1050. //
  1051. if (0xffff == IPIDListRecv[i]) {
  1052. IPIDListRecv[i] = IPID;
  1053. break;
  1054. }
  1055. }
  1056. NdisReleaseSpinLock(&IPIDListLockRecv);
  1057. if (i == PORT_RANGE) {
  1058. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("Couldn't find an empty IPID - Bailing \n"));
  1059. }
  1060. }
  1061. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: *UDP* Address: SRC = %x DST = %x, Port S : %x, Port D: %x\n",
  1062. IPH->iph_src,
  1063. IPH->iph_dest,
  1064. UDPH->uh_src,
  1065. UDPH->uh_dest));
  1066. break;
  1067. case IPPROTO_RAW:
  1068. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol RAW\n"));
  1069. break;
  1070. case IPPROTO_IGMP:
  1071. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol IGMP\n"));
  1072. break;
  1073. case IPPROTO_ICMP:
  1074. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol TCMP\n"));
  1075. break;
  1076. default:
  1077. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_RECV, ("[TimeStmpReceiveIndication]: Protocol - UNKNOWN (%d)\n", IPH->iph_protocol));
  1078. //DbgBreakPoint();
  1079. }
  1080. }
  1081. }
  1082. }
  1083. RECV_FAILURE:
  1084. return TRUE;
  1085. }
  1086. VOID
  1087. TimeStmpSetInformation (
  1088. IN PPS_PIPE_CONTEXT PipeContext,
  1089. IN PPS_FLOW_CONTEXT FlowContext,
  1090. IN NDIS_OID Oid,
  1091. IN ULONG Len,
  1092. IN void *Data)
  1093. {
  1094. PPS_PIPE_CONTEXT Pipe = PipeContext;
  1095. PPS_FLOW_CONTEXT Flow = FlowContext;
  1096. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_OID, ("[TimeStmpSetInformation]:\n"));
  1097. (*Pipe->NextComponent->SetInformation)(
  1098. Pipe->NextComponentContext,
  1099. (Flow)?Flow->NextComponentContext:0,
  1100. Oid,
  1101. Len,
  1102. Data);
  1103. }
  1104. VOID
  1105. TimeStmpQueryInformation (
  1106. IN PPS_PIPE_CONTEXT PipeContext,
  1107. IN PPS_FLOW_CONTEXT FlowContext,
  1108. IN NDIS_OID Oid,
  1109. IN ULONG Len,
  1110. IN PVOID Data,
  1111. IN OUT PULONG BytesWritten,
  1112. IN OUT PULONG BytesNeeded,
  1113. IN OUT PNDIS_STATUS Status)
  1114. {
  1115. PPS_PIPE_CONTEXT Pipe = PipeContext;
  1116. PPS_FLOW_CONTEXT Flow = FlowContext;
  1117. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_OID, ("[TimeStmpQueryInformation]:\n"));
  1118. (*Pipe->NextComponent->QueryInformation)(
  1119. Pipe->NextComponentContext,
  1120. (Flow)?Flow->NextComponentContext:0,
  1121. Oid,
  1122. Len,
  1123. Data,
  1124. BytesWritten,
  1125. BytesNeeded,
  1126. Status);
  1127. }
  1128. NDIS_STATUS
  1129. TimeStmpCreateClassMap (
  1130. IN PPS_PIPE_CONTEXT PipeContext,
  1131. IN HANDLE PsClassMapContext,
  1132. IN PTC_CLASS_MAP_FLOW ClassMap,
  1133. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
  1134. )
  1135. {
  1136. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_CLASS_MAP, ("[TimeStmpCreateClassMap]: \n"));
  1137. return (*PipeContext->NextComponent->CreateClassMap)(
  1138. PipeContext->NextComponentContext,
  1139. PsClassMapContext,
  1140. ClassMap,
  1141. ComponentClassMapContext->NextComponentContext);
  1142. }
  1143. NDIS_STATUS
  1144. TimeStmpDeleteClassMap (
  1145. IN PPS_PIPE_CONTEXT PipeContext,
  1146. IN PPS_CLASS_MAP_CONTEXT ComponentClassMapContext
  1147. )
  1148. {
  1149. TimeStmpTrace(TS_DBG_TRACE, TS_DBG_CLASS_MAP, ("[TimeStmpDeleteClassMap]: \n"));
  1150. return (*PipeContext->NextComponent->DeleteClassMap)(
  1151. PipeContext->NextComponentContext,
  1152. ComponentClassMapContext->NextComponentContext);
  1153. }
  1154. NTSTATUS
  1155. DriverEntry(
  1156. IN PDRIVER_OBJECT DriverObject,
  1157. IN PUNICODE_STRING RegistryPath
  1158. )
  1159. {
  1160. PSI_INFO Component;
  1161. NDIS_HANDLE ConfigHandle;
  1162. NDIS_STATUS Status;
  1163. NDIS_STRING ComponentKey = NDIS_STRING_CONST("DisplayName");
  1164. NDIS_STRING ComponentName = NDIS_STRING_CONST("TimeStmp");
  1165. PNDIS_CONFIGURATION_PARAMETER pConfigParam;
  1166. NDIS_STRING PsParamKey;
  1167. PWSTR p = RegistryPath->Buffer + RegistryPath->Length;
  1168. PS_DEBUG_INFO Dbg;
  1169. ULONG i = 0;
  1170. // The last word of Registry Path points to the driver name.
  1171. // NdisOpenProtocol needs that name!
  1172. while(p != RegistryPath->Buffer && *p != L'\\')
  1173. p-- ;
  1174. p++;
  1175. RtlInitUnicodeString(&PsParamKey, p);
  1176. DbgPrint("PsParamKey:%s\n", PsParamKey);
  1177. NdisOpenProtocolConfiguration(&Status, &ConfigHandle, &PsParamKey);
  1178. DbgPrint("Status of NdisOpenProtocol:%x\n", Status);
  1179. if (!NT_SUCCESS(Status)) {
  1180. goto failure;
  1181. }
  1182. //
  1183. // Check if psched is installed by opening it.
  1184. // If it fails, we dont load either.
  1185. //
  1186. Status = CheckForPsched();
  1187. if (!NT_SUCCESS(Status)) {
  1188. DbgPrint("PSCHED is NOT installed. Timestmp is bailing too\n");
  1189. goto failure;
  1190. }
  1191. IoctlInitialize(DriverObject);
  1192. // this list maintains a list of all ports that need to be timestamped.
  1193. InitializeListHead(&PortList);
  1194. NdisAllocateSpinLock(&PortSpinLock);
  1195. DriverObject->DriverUnload = TimeStmpUnload;
  1196. //
  1197. // We need to keep track of IPIDs for dealing with fragments
  1198. // that we need to stamp...
  1199. //
  1200. for (i = 0; i < PORT_RANGE; i++) {
  1201. IPIDList[i] = 0xffff;
  1202. }
  1203. NdisAllocateSpinLock(&IPIDListLock);
  1204. //
  1205. // Do the same for the receive side.
  1206. //
  1207. for (i = 0; i < PORT_RANGE; i++) {
  1208. IPIDListRecv[i] = 0xffff;
  1209. }
  1210. NdisAllocateSpinLock(&IPIDListLockRecv);
  1211. if ( NT_SUCCESS( Status ))
  1212. {
  1213. // Read the name of the component from the registry
  1214. #if 0
  1215. NdisReadConfiguration( &Status,
  1216. &pConfigParam,
  1217. ConfigHandle,
  1218. &ComponentKey,
  1219. NdisParameterString);
  1220. if( NT_SUCCESS( Status ))
  1221. {
  1222. RtlInitUnicodeString(&Component.ComponentName,
  1223. pConfigParam->ParameterData.StringData.Buffer);
  1224. #else
  1225. RtlInitUnicodeString(&Component.ComponentName, ComponentName.Buffer);
  1226. #endif
  1227. Component.Version = PS_COMPONENT_CURRENT_VERSION;
  1228. Component.PacketReservedLength = 0;
  1229. Component.PipeContextLength = sizeof(PS_PIPE_CONTEXT);
  1230. Component.FlowContextLength = sizeof(PS_FLOW_CONTEXT);
  1231. Component.ClassMapContextLength = sizeof(PS_CLASS_MAP_CONTEXT);
  1232. Component.SupportedOidsLength = 0;
  1233. Component.SupportedOidList = 0;
  1234. Component.SupportedGuidsLength = 0;
  1235. Component.SupportedGuidList = 0;
  1236. Component.InitializePipe = TimeStmpInitializePipe;
  1237. Component.ModifyPipe = TimeStmpModifyPipe;
  1238. Component.DeletePipe = TimeStmpDeletePipe;
  1239. Component.CreateFlow = TimeStmpCreateFlow;
  1240. Component.ModifyFlow = TimeStmpModifyFlow;
  1241. Component.DeleteFlow = TimeStmpDeleteFlow;
  1242. Component.CreateClassMap = TimeStmpCreateClassMap;
  1243. Component.DeleteClassMap = TimeStmpDeleteClassMap;
  1244. Component.SubmitPacket = TimeStmpSubmitPacket;
  1245. Component.ReceivePacket = TimeStmpReceivePacket;
  1246. Component.ReceiveIndication = TimeStmpReceiveIndication;
  1247. Component.SetInformation = TimeStmpSetInformation;
  1248. Component.QueryInformation = TimeStmpQueryInformation;
  1249. //
  1250. // Call Psched's RegisterPsComponent
  1251. //
  1252. Status = RegisterPsComponent(&Component, sizeof(Component),
  1253. &Dbg);
  1254. if(Status != NDIS_STATUS_SUCCESS)
  1255. {
  1256. DbgPrint("Status of RegisterPsComponent%x\n", Status);
  1257. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_INIT,
  1258. ("DriverEntry: RegisterPsComponent Failed \n"));
  1259. }
  1260. else
  1261. {
  1262. DbgPrint("Status of RegisterPsComponent:%x\n", Status);
  1263. }
  1264. #if 0
  1265. }
  1266. else
  1267. {
  1268. DbgPrint("Status of NdisReadProtocol:%x\n", Status);
  1269. DbgBreakPoint();
  1270. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_INIT,
  1271. ("DriverEntry: ComponentName not specified \n"));
  1272. }
  1273. #endif
  1274. }
  1275. else
  1276. {
  1277. DbgPrint("Status of NdisOpenProtocol:%x\n", Status);
  1278. TimeStmpTrace(TS_DBG_DEATH, TS_DBG_INIT,
  1279. ("DriverEntry: Can't read driver information in registry"
  1280. "\n"));
  1281. }
  1282. failure:
  1283. return Status;
  1284. }
  1285. //
  1286. // The following function checks for the existence of PSCHED on the machine.
  1287. // The assumption being that PSCHED gets loaded before TimeStmp on a system.
  1288. // If we can open the device, it means that PSCHED is on, otherwise, we bail.
  1289. // This fix is for Bug - 321618
  1290. //
  1291. NTSTATUS
  1292. CheckForPsched(
  1293. VOID
  1294. )
  1295. {
  1296. NTSTATUS status;
  1297. IO_STATUS_BLOCK ioStatusBlock;
  1298. OBJECT_ATTRIBUTES objectAttr;
  1299. InitializeObjectAttributes(
  1300. &objectAttr,
  1301. &PschedDriverName,
  1302. OBJ_CASE_INSENSITIVE,
  1303. NULL,
  1304. NULL);
  1305. status = NtCreateFile(
  1306. &PschedHandle,
  1307. GENERIC_READ,
  1308. &objectAttr,
  1309. &ioStatusBlock,
  1310. NULL,
  1311. FILE_ATTRIBUTE_NORMAL,
  1312. FILE_SHARE_READ,
  1313. FILE_OPEN,
  1314. FILE_SYNCHRONOUS_IO_NONALERT,
  1315. NULL,
  1316. 0L);
  1317. if (!NT_SUCCESS(status)) {
  1318. return status;
  1319. } else {
  1320. NtClose(PschedHandle);
  1321. }
  1322. return status;
  1323. }
  1324. PPORT_ENTRY
  1325. CheckInPortList(USHORT Port) {
  1326. PLIST_ENTRY ListEntry;
  1327. PPORT_ENTRY pPortEntry;
  1328. NdisAcquireSpinLock(&PortSpinLock);
  1329. ListEntry = PortList.Flink;
  1330. while (ListEntry != &PortList) {
  1331. pPortEntry = CONTAINING_RECORD(ListEntry, PORT_ENTRY, Linkage);
  1332. if (Port == pPortEntry->Port) {
  1333. //DbgPrint("Found Port%d\n", Port);
  1334. NdisReleaseSpinLock(&PortSpinLock);
  1335. return pPortEntry;
  1336. } else {
  1337. ListEntry = ListEntry->Flink;
  1338. //DbgPrint("NOT Found Trying NEXT\n");
  1339. }
  1340. }
  1341. NdisReleaseSpinLock(&PortSpinLock);
  1342. //DbgPrint("NOT Found returning from function\n");
  1343. return NULL;
  1344. }