Leaked source code of windows server 2003
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.

513 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 ICL Data
  4. Module Name:
  5. llctrace.c
  6. Abstract:
  7. Module implements simple trace buffer management.
  8. The application must povides a trace buffer and
  9. read it by polling.
  10. THIS MODULE HAS BEEN IMPLEMENTED ONLY FOR THE DATA LINK
  11. EMULATION ENVIRONMENT ON USER LEVEL.
  12. Author:
  13. Antti Saarenheimo (o-anttis) 10-OCT-1991
  14. Environment:
  15. Kernel mode
  16. Revision History:
  17. --*/
  18. #include <llc.h>
  19. #ifndef max
  20. #include <stdlib.h>
  21. #endif
  22. #ifdef TRACE_ENABLED
  23. BOOLEAN TraceEnabled;
  24. static PLLC_TRACE_HEADER pTraceBufferBase;
  25. static PLLC_TRACE_HEADER pTraceBufferTop;
  26. static PLLC_TRACE_HEADER pTraceBufferHead;
  27. static NDIS_SPIN_LOCK TraceLock;
  28. static ULONG TraceFlags;
  29. UCHAR GetHexDigit(
  30. UINT Ch
  31. );
  32. PUCHAR
  33. GetHexString(
  34. PUCHAR pDest,
  35. UINT Length,
  36. PUCHAR Buffer
  37. );
  38. DLC_STATUS
  39. LlcTraceInitialize(
  40. IN PVOID pUserTraceBuffer,
  41. IN ULONG UserTraceBufferSize,
  42. IN ULONG UserTraceFlags
  43. )
  44. {
  45. //
  46. // This small piece of code is not multiprocessors safe,
  47. // but nobody will ever find it ...
  48. //
  49. if (TraceEnabled)
  50. {
  51. return DLC_STATUS_DUPLICATE_COMMAND;
  52. }
  53. if (UserTraceBufferSize < LLC_MIN_TRACE_BUFFER)
  54. {
  55. return DLC_STATUS_INVALID_BUFFER_LENGTH;
  56. }
  57. RtlZeroMemory( pUserTraceBuffer, (UINT)UserTraceBufferSize );
  58. ALLOCATE_SPIN_LOCK( &TraceLock );
  59. pTraceBufferBase = pTraceBufferHead = (PLLC_TRACE_HEADER)pUserTraceBuffer;
  60. pTraceBufferHead->Event = LLC_TRACE_END_OF_DATA;
  61. pTraceBufferTop =
  62. &pTraceBufferBase[ UserTraceBufferSize / sizeof(LLC_TRACE_HEADER) ];
  63. TraceFlags = UserTraceFlags;
  64. TraceEnabled = TRUE;
  65. return STATUS_SUCCESS;
  66. }
  67. VOID
  68. LlcTraceClose(
  69. VOID
  70. )
  71. {
  72. if (TraceEnabled)
  73. {
  74. TraceEnabled = FALSE;
  75. DEALLOCATE_SPIN_LOCK( &TraceLock );
  76. }
  77. }
  78. VOID
  79. LlcTraceWrite(
  80. IN UINT Event,
  81. IN UCHAR AdapterNumber,
  82. IN UINT DataBufferSize,
  83. IN PVOID pDataBuffer
  84. )
  85. {
  86. //if ((AdapterNumber & 0x7f) != 0)
  87. // return;
  88. if (TraceEnabled)
  89. {
  90. ACQUIRE_SPIN_LOCK( &TraceLock );
  91. if ((ULONG)(&pTraceBufferHead[1]) >= (ULONG)pTraceBufferTop)
  92. {
  93. pTraceBufferHead = (PLLC_TRACE_HEADER)pTraceBufferBase;
  94. }
  95. pTraceBufferHead->Event = (USHORT)Event;
  96. pTraceBufferHead->AdapterNumber = AdapterNumber;
  97. pTraceBufferHead->TimerTick = AbsoluteTime;
  98. pTraceBufferHead->DataLength = (UCHAR)
  99. #ifdef min
  100. min( TRACE_DATA_LENGTH, DataBufferSize );
  101. #else
  102. __min( TRACE_DATA_LENGTH, DataBufferSize );
  103. #endif
  104. memcpy(
  105. pTraceBufferHead->Buffer,
  106. pDataBuffer,
  107. pTraceBufferHead->DataLength
  108. );
  109. pTraceBufferHead++;
  110. pTraceBufferHead->Event = LLC_TRACE_END_OF_DATA;
  111. RELEASE_SPIN_LOCK( &TraceLock );
  112. }
  113. }
  114. #ifdef OS2_EMU_DLC
  115. //
  116. // Procedure makes the post mortem dump of the given number of last frames.
  117. // The output should look very much like in Sniffer.
  118. // This routine doesn't supprot source routing info, but its implementatin
  119. // should not be a very big thing.
  120. //
  121. VOID
  122. LlcTraceDump(
  123. IN UINT LastEvents,
  124. IN UINT AdapterNumber,
  125. IN PUCHAR pRemoteNode
  126. )
  127. {
  128. PUCHAR pDest, pSrc, pCommand, pDlcHeader, pDirection, pTmp;
  129. UINT i;
  130. UCHAR Buffer1[13], Buffer2[13];
  131. UCHAR CmdResp, PollFinal;
  132. LLC_HEADER LlcHeader;
  133. BOOLEAN IsEthernet;
  134. PLLC_TRACE_HEADER pTrace;
  135. UCHAR DataBuffer[18];
  136. USHORT EthernetType;
  137. RtlZeroMemory( DataBuffer, sizeof( DataBuffer ));
  138. LlcTraceWrite(
  139. LLC_TRACE_RECEIVE_FRAME, AdapterNumber, sizeof(DataBuffer), DataBuffer );
  140. if (!TraceEnabled)
  141. return;
  142. ACQUIRE_SPIN_LOCK( &TraceLock );
  143. printf(
  144. "# Time Adpt Local Node Remote Node Dsp Ssp Cmd Nr Ns\n");
  145. //0---------1---------2---------3---------4---------5---------6---------7-----
  146. //5 10 5 13 13 4 4 9 4 4
  147. for (
  148. pTrace = pTraceBufferHead, i = 0;
  149. i < LastEvents;
  150. i++)
  151. {
  152. EthernetType = 0;
  153. if (pTrace != pTraceBufferBase)
  154. {
  155. pTrace--;
  156. }
  157. else
  158. {
  159. pTrace = pTraceBufferTop - 2;
  160. }
  161. if (pTrace->Event == LLC_TRACE_END_OF_DATA)
  162. {
  163. break;
  164. }
  165. //
  166. // The highest bit is set in the adapter number, if
  167. // it's a token-ring adapter.
  168. //
  169. if (pTrace->AdapterNumber & 0x80)
  170. {
  171. IsEthernet = FALSE;
  172. }
  173. else
  174. IsEthernet = TRUE;
  175. pDlcHeader = &pTrace->Buffer[14];
  176. if (IsEthernet)
  177. {
  178. pSrc = &pTrace->Buffer[6];
  179. pDest = pTrace->Buffer;
  180. //
  181. // Discard all non ieee 802.2 frames, but support
  182. // the SNA dix headers.
  183. //
  184. if (pTrace->Buffer[12] == 0x80 &&
  185. pTrace->Buffer[13] == 0xd5)
  186. {
  187. pDlcHeader = &pTrace->Buffer[17];
  188. }
  189. else if (pTrace->Buffer[12] >= 64)
  190. {
  191. EthernetType = (USHORT)
  192. (((USHORT)pTrace->Buffer[12] << 8) +
  193. pTrace->Buffer[13]
  194. );
  195. }
  196. }
  197. else
  198. {
  199. pSrc = &pTrace->Buffer[8];
  200. pDest = &pTrace->Buffer[2];
  201. //
  202. // Skip the source souting info
  203. //
  204. if (pTrace->Buffer[8] & 0x80)
  205. pDlcHeader += pTrace->Buffer[14] & 0x1f;
  206. //
  207. // Discard all non ieee 802.2 frames
  208. //
  209. if (pTrace->Buffer[1] != 0x40)
  210. continue;
  211. }
  212. memcpy( (PUCHAR)&LlcHeader, pDlcHeader, 4 );
  213. if (AdapterNumber != -1 &&
  214. AdapterNumber != ((UINT)pTrace->AdapterNumber & 0x7f))
  215. continue;
  216. if (pTrace->Event == LLC_TRACE_SEND_FRAME)
  217. {
  218. if (pRemoteNode != NULL && memcmp( pDest, pRemoteNode, 6))
  219. continue;
  220. pTmp = pDest;
  221. pDest = pSrc;
  222. pSrc = pTmp;
  223. pDirection = "->";
  224. }
  225. else if (pTrace->Event == LLC_TRACE_RECEIVE_FRAME)
  226. {
  227. if (pRemoteNode != NULL && memcmp( pSrc, pRemoteNode, 6))
  228. continue;
  229. pDirection = "<-";
  230. }
  231. else
  232. {
  233. continue;
  234. }
  235. if (EthernetType != 0)
  236. {
  237. printf(
  238. "%-4u %-9lu %3u %12s %2s %12s DIX type %x\n",
  239. i,
  240. pTrace->TimerTick,
  241. pTrace->AdapterNumber & 0x7f,
  242. GetHexString( pDest, 6, Buffer1 ),
  243. pDirection,
  244. GetHexString( pSrc, 6, Buffer2 ),
  245. EthernetType
  246. );
  247. }
  248. //
  249. // Handle first I frames, they are the most common!
  250. //
  251. else if (!(LlcHeader.U.Command & LLC_NOT_I_FRAME))
  252. {
  253. PollFinal = ' ';
  254. if (LlcHeader.I.Ssap & LLC_SSAP_RESPONSE)
  255. {
  256. CmdResp = 'r';
  257. if (LlcHeader.I.Nr & LLC_I_S_POLL_FINAL)
  258. {
  259. PollFinal = 'f';
  260. }
  261. }
  262. else
  263. {
  264. CmdResp = 'c';
  265. if (LlcHeader.I.Nr & LLC_I_S_POLL_FINAL)
  266. {
  267. PollFinal = 'p';
  268. }
  269. }
  270. pCommand = "I";
  271. printf(
  272. "%-4u %-9lu %3u %12s %2s %12s %-2x %-2x %5s-%c%c %-3u %-3u\n",
  273. i,
  274. pTrace->TimerTick,
  275. pTrace->AdapterNumber & 0x7f,
  276. GetHexString( pDest, 6, Buffer1 ),
  277. pDirection,
  278. GetHexString( pSrc, 6, Buffer2 ),
  279. LlcHeader.U.Dsap,
  280. LlcHeader.U.Ssap & 0xfe,
  281. pCommand,
  282. CmdResp,
  283. PollFinal,
  284. LlcHeader.I.Nr >> 1,
  285. LlcHeader.I.Ns >> 1
  286. );
  287. }
  288. else if (!(LlcHeader.S.Command & LLC_U_TYPE_BIT))
  289. {
  290. //
  291. // Handle S (Supervisory) commands (RR, REJ, RNR)
  292. //
  293. switch (LlcHeader.S.Command)
  294. {
  295. case LLC_RR:
  296. pCommand = "RR";
  297. break;
  298. case LLC_RNR:
  299. pCommand = "RNR";
  300. break;
  301. case LLC_REJ:
  302. pCommand = "REJ";
  303. break;
  304. default:
  305. pCommand = "INV";
  306. break;
  307. };
  308. //
  309. // The valid frames has modulo: Va <= Nr <= Vs,
  310. // Ie. the Receive sequence number should belong to
  311. // a frame that has been sent but not acknowledged.
  312. // The extra check in the beginning makes the most common
  313. // code path faster: usually the other is waiting the next frame.
  314. // (keep the rest code the same as in I path, even a very
  315. // primitive optimizer will puts these code paths together)
  316. //
  317. PollFinal = ' ';
  318. if (LlcHeader.S.Ssap & LLC_SSAP_RESPONSE)
  319. {
  320. CmdResp = 'r';
  321. if (LlcHeader.S.Nr & LLC_I_S_POLL_FINAL)
  322. {
  323. PollFinal = 'f';
  324. }
  325. }
  326. else
  327. {
  328. CmdResp = 'c';
  329. if (LlcHeader.S.Nr & LLC_I_S_POLL_FINAL)
  330. {
  331. PollFinal = 'p';
  332. }
  333. }
  334. printf(
  335. "%-4u %-9lu %3u %12s %2s %12s %-2x %-2x %5s-%c%c %-3u\n",
  336. i,
  337. pTrace->TimerTick,
  338. pTrace->AdapterNumber & 0x7f,
  339. GetHexString( pDest, 6, Buffer1 ),
  340. pDirection,
  341. GetHexString( pSrc, 6, Buffer2 ),
  342. LlcHeader.U.Dsap,
  343. LlcHeader.U.Ssap & 0xfe,
  344. pCommand,
  345. CmdResp,
  346. PollFinal,
  347. LlcHeader.I.Nr >> 1
  348. );
  349. }
  350. else
  351. {
  352. //
  353. // Handle U (Unnumbered) command frames
  354. // (FRMR, DM, UA, DISC, SABME, XID, TEST)
  355. switch (LlcHeader.U.Command & ~LLC_U_POLL_FINAL)
  356. {
  357. case LLC_UI:
  358. pCommand = "UI";
  359. break;
  360. case LLC_DISC:
  361. pCommand = "DISC";
  362. break;
  363. case LLC_SABME:
  364. pCommand = "SABME";
  365. break;
  366. case LLC_DM:
  367. pCommand = "DM";
  368. break;
  369. case LLC_UA:
  370. pCommand = "UA";
  371. break;
  372. case LLC_FRMR:
  373. pCommand = "FRMR";
  374. break;
  375. case LLC_TEST:
  376. pCommand = "TEST";
  377. break;
  378. case LLC_XID:
  379. pCommand = "XID";
  380. break;
  381. default:
  382. pCommand = "INV";
  383. break;
  384. };
  385. //
  386. // We set an uniform poll/final bit for procedure call
  387. //
  388. PollFinal = ' ';
  389. if (LlcHeader.U.Command & LLC_U_POLL_FINAL)
  390. {
  391. if (LlcHeader.U.Ssap & 1)
  392. {
  393. PollFinal = 'f';
  394. }
  395. else
  396. {
  397. PollFinal = 'p';
  398. }
  399. }
  400. if (LlcHeader.U.Ssap & 1)
  401. {
  402. CmdResp = 'r';
  403. }
  404. else
  405. {
  406. CmdResp = 'c';
  407. }
  408. printf(
  409. "%-4u %-9lu %3u %12s %2s %12s %-2x %-2x %5s-%c%c\n",
  410. i,
  411. pTrace->TimerTick,
  412. pTrace->AdapterNumber & 0x7f,
  413. GetHexString( pDest, 6, Buffer1 ),
  414. pDirection,
  415. GetHexString( pSrc, 6, Buffer2 ),
  416. LlcHeader.U.Dsap,
  417. LlcHeader.U.Ssap & 0xfe,
  418. pCommand,
  419. CmdResp,
  420. PollFinal
  421. );
  422. }
  423. }
  424. RELEASE_SPIN_LOCK( &TraceLock );
  425. }
  426. UCHAR GetHexDigit(
  427. UINT Ch
  428. )
  429. {
  430. if (Ch <= 9)
  431. return (UCHAR)('0' + (UCHAR)Ch);
  432. else
  433. return (UCHAR)('A' + (UCHAR)Ch - 10);
  434. }
  435. PUCHAR
  436. GetHexString(
  437. PUCHAR pDest,
  438. UINT Length,
  439. PUCHAR Buffer
  440. )
  441. {
  442. UINT i;
  443. for (i = 0; i < (Length * 2); i += 2)
  444. {
  445. Buffer[i] = GetHexDigit( *pDest >> 4 );
  446. Buffer[i+1] = GetHexDigit( *pDest & 0x0f );
  447. pDest++;
  448. }
  449. Buffer[i] = 0;
  450. return Buffer;
  451. }
  452. VOID
  453. LlcTraceDumpAndReset(
  454. IN UINT LastEvents,
  455. IN UINT AdapterNumber,
  456. IN PUCHAR pRemoteNode
  457. )
  458. {
  459. LlcTraceDump( LastEvents, AdapterNumber, pRemoteNode );
  460. ACQUIRE_SPIN_LOCK( &TraceLock );
  461. if ((ULONG)(&pTraceBufferHead[1]) >= (ULONG)pTraceBufferTop)
  462. {
  463. pTraceBufferHead = (PLLC_TRACE_HEADER)pTraceBufferBase;
  464. }
  465. else
  466. pTraceBufferHead++;
  467. RELEASE_SPIN_LOCK( &TraceLock );
  468. }
  469. #endif
  470. #endif // TRACE_ENABLED