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.

893 lines
18 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. cxport.c
  5. Abstract:
  6. Common Transport Environment utility functions for the NT environment
  7. Author:
  8. Mike Massa (mikemas) Aug 11, 1993
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 08-11-93 created
  13. Notes:
  14. --*/
  15. #pragma warning(push)
  16. #pragma warning(disable:4115) // named type definition in parentheses ntddk.h
  17. #include <ntddk.h>
  18. #pragma warning(pop)
  19. #include <ndis.h>
  20. #include <cxport.h>
  21. #include <tdistat.h>
  22. //
  23. // Mark pageable code
  24. //
  25. #ifdef ALLOC_PRAGMA
  26. #pragma alloc_text(PAGE, CTELogEvent)
  27. #endif // ALLOC_PRAGMA
  28. //
  29. // Local variables
  30. //
  31. ULONG CTEpTimeIncrement = 0; // used to convert kernel clock ticks to 100ns.
  32. LIST_ENTRY CTEBlockListHead;
  33. KSPIN_LOCK CTEBlockSpinLock;
  34. // Used in the conversion of 100ns times to milliseconds.
  35. static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  36. //
  37. // Macros
  38. //
  39. //++
  40. //
  41. // LARGE_INTEGER
  42. // CTEConvertMillisecondsTo100ns(
  43. // IN LARGE_INTEGER MsTime
  44. // );
  45. //
  46. // Routine Description:
  47. //
  48. // Converts time expressed in hundreds of nanoseconds to milliseconds.
  49. //
  50. // Arguments:
  51. //
  52. // MsTime - Time in milliseconds.
  53. //
  54. // Return Value:
  55. //
  56. // Time in hundreds of nanoseconds.
  57. //
  58. //--
  59. #define CTEConvertMillisecondsTo100ns(MsTime) \
  60. RtlExtendedIntegerMultiply(MsTime, 10000)
  61. //++
  62. //
  63. // LARGE_INTEGER
  64. // CTEConvert100nsToMilliseconds(
  65. // IN LARGE_INTEGER HnsTime
  66. // );
  67. //
  68. // Routine Description:
  69. //
  70. // Converts time expressed in hundreds of nanoseconds to milliseconds.
  71. //
  72. // Arguments:
  73. //
  74. // HnsTime - Time in hundreds of nanoseconds.
  75. //
  76. // Return Value:
  77. //
  78. // Time in milliseconds.
  79. //
  80. //--
  81. #define SHIFT10000 13
  82. extern LARGE_INTEGER Magic10000;
  83. #define CTEConvert100nsToMilliseconds(HnsTime) \
  84. RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
  85. //
  86. // Local functions
  87. //
  88. VOID
  89. CTEpInitialize(
  90. VOID
  91. )
  92. /*++
  93. Routine Description:
  94. Initializes internal module state.
  95. Arguments:
  96. None.
  97. Return Value:
  98. None.
  99. --*/
  100. {
  101. CTEpTimeIncrement = KeQueryTimeIncrement();
  102. KeInitializeSpinLock(&CTEBlockSpinLock);
  103. InitializeListHead(&CTEBlockListHead);
  104. }
  105. VOID
  106. CTEpEventHandler(
  107. IN PVOID Context
  108. )
  109. /*++
  110. Routine Description:
  111. Internal handler for scheduled CTE Events. Conforms to calling convention
  112. for ExWorkerThread handlers. Calls the CTE handler registered for this
  113. event.
  114. Arguments:
  115. Context - Work item to process.
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. CTEEvent *Event;
  121. CTELockHandle Handle;
  122. CTEEventRtn Handler;
  123. PVOID Arg;
  124. #if DBG
  125. KIRQL StartingIrql;
  126. StartingIrql = KeGetCurrentIrql();
  127. #endif
  128. Event = (CTEEvent *) Context;
  129. CTEGetLock(&(Event->ce_lock), &Handle);
  130. ASSERT(Event->ce_scheduled);
  131. Handler = Event->ce_handler;
  132. Arg = Event->ce_arg;
  133. Event->ce_scheduled = 0;
  134. CTEFreeLock(&(Event->ce_lock), Handle);
  135. Handler(Event, Arg);
  136. #if DBG
  137. if (KeGetCurrentIrql() != StartingIrql) {
  138. DbgPrint(
  139. "CTEpEventHandler: routine %lx , event %lx returned at raised IRQL\n",
  140. Handler, Event
  141. );
  142. DbgBreakPoint();
  143. }
  144. #endif
  145. }
  146. VOID
  147. CTEpTimerHandler(
  148. IN PKDPC Dpc,
  149. IN PVOID DeferredContext,
  150. IN PVOID SystemArgument1,
  151. IN PVOID SystemArgument2
  152. )
  153. /*++
  154. Routine Description:
  155. Internal handler for scheduled CTE Timers. Conforms to calling convention
  156. for NT DPC handlers. Calls the CTE handler registered for this timer.
  157. Arguments:
  158. Dpc - Pointer to the DPC routine being run.
  159. DeferredContext - Private context for this instance of the DPC.
  160. SystemArgument1 - Additional argument.
  161. SystemArgument2 - Additional argument.
  162. Return Value:
  163. None.
  164. --*/
  165. {
  166. CTETimer *Timer;
  167. UNREFERENCED_PARAMETER(Dpc);
  168. UNREFERENCED_PARAMETER(SystemArgument1);
  169. UNREFERENCED_PARAMETER(SystemArgument2);
  170. Timer = (CTETimer *) DeferredContext;
  171. (*Timer->t_handler)((CTEEvent *)Timer, Timer->t_arg);
  172. }
  173. //
  174. // Exported functions.
  175. //
  176. int
  177. CTEInitialize(
  178. VOID
  179. )
  180. /*++
  181. Routine Description:
  182. An empty initialization routine for backward compatibility.
  183. Arguments:
  184. None.
  185. Return Value:
  186. Non-zero.
  187. --*/
  188. {
  189. return 1;
  190. }
  191. void
  192. CTEInitEvent(
  193. CTEEvent *Event,
  194. CTEEventRtn Handler
  195. )
  196. /*++
  197. Routine Description:
  198. Initializes a CTE Event variable.
  199. Arguments:
  200. Event - Event variable to initialize.
  201. Handler - Handler routine for this event variable.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. ASSERT(Handler != NULL);
  207. Event->ce_handler = Handler;
  208. Event->ce_scheduled = 0;
  209. CTEInitLock(&(Event->ce_lock));
  210. ExInitializeWorkItem(&(Event->ce_workitem), CTEpEventHandler, Event);
  211. }
  212. int
  213. CTEScheduleCriticalEvent(
  214. IN CTEEvent *Event,
  215. IN void *Argument OPTIONAL
  216. )
  217. /*++
  218. Routine Description:
  219. Schedules a routine to be executed later in a different context. In the
  220. NT environment, the event is implemented using Executive worker threads.
  221. Arguments:
  222. Event - Pointer to a CTE Event variable
  223. Argument - An argument to pass to the event handler when it is called
  224. Return Value:
  225. 0 if the event could not be scheduled. Nonzero otherwise.
  226. --*/
  227. {
  228. CTELockHandle Handle;
  229. CTEGetLock(&(Event->ce_lock), &Handle);
  230. if (!(Event->ce_scheduled)) {
  231. Event->ce_scheduled = 1;
  232. Event->ce_arg = Argument;
  233. ExQueueWorkItem(
  234. &(Event->ce_workitem),
  235. CriticalWorkQueue
  236. );
  237. }
  238. CTEFreeLock(&(Event->ce_lock), Handle);
  239. return(1);
  240. }
  241. int
  242. CTEScheduleEvent(
  243. IN CTEEvent *Event,
  244. IN void *Argument OPTIONAL
  245. )
  246. /*++
  247. Routine Description:
  248. Schedules a routine to be executed later in a different context. In the
  249. NT environment, the event is implemented using Executive worker threads.
  250. Arguments:
  251. Event - Pointer to a CTE Event variable
  252. Argument - An argument to pass to the event handler when it is called
  253. Return Value:
  254. 0 if the event could not be scheduled. Nonzero otherwise.
  255. --*/
  256. {
  257. CTELockHandle Handle;
  258. CTEGetLock(&(Event->ce_lock), &Handle);
  259. if (!(Event->ce_scheduled)) {
  260. Event->ce_scheduled = 1;
  261. Event->ce_arg = Argument;
  262. ExQueueWorkItem(
  263. &(Event->ce_workitem),
  264. DelayedWorkQueue
  265. );
  266. }
  267. CTEFreeLock(&(Event->ce_lock), Handle);
  268. return(1);
  269. }
  270. int
  271. CTEScheduleDelayedEvent(
  272. IN CTEEvent *Event,
  273. IN void *Argument OPTIONAL
  274. )
  275. /*++
  276. Routine Description:
  277. Schedules a routine to be executed later in a different context. In the
  278. NT environment, the event is implemented using Executive worker threads.
  279. Arguments:
  280. Event - Pointer to a CTE Event variable
  281. Argument - An argument to pass to the event handler when it is called
  282. Return Value:
  283. 0 if the event could not be scheduled. Nonzero otherwise.
  284. --*/
  285. {
  286. CTELockHandle Handle;
  287. CTEGetLock(&(Event->ce_lock), &Handle);
  288. if (!(Event->ce_scheduled)) {
  289. Event->ce_scheduled = 1;
  290. Event->ce_arg = Argument;
  291. ExQueueWorkItem(
  292. &(Event->ce_workitem),
  293. DelayedWorkQueue
  294. );
  295. }
  296. CTEFreeLock(&(Event->ce_lock), Handle);
  297. return(1);
  298. }
  299. void
  300. CTEInitTimer(
  301. CTETimer *Timer
  302. )
  303. /*++
  304. Routine Description:
  305. Initializes a CTE Timer variable.
  306. Arguments:
  307. Timer - Timer variable to initialize.
  308. Return Value:
  309. None.
  310. --*/
  311. {
  312. Timer->t_handler = NULL;
  313. Timer->t_arg = NULL;
  314. KeInitializeDpc(&(Timer->t_dpc), CTEpTimerHandler, Timer);
  315. KeInitializeTimer(&(Timer->t_timer));
  316. }
  317. void *
  318. CTEStartTimer(
  319. CTETimer *Timer,
  320. unsigned long DueTime,
  321. CTEEventRtn Handler,
  322. void *Context
  323. )
  324. /*++
  325. Routine Description:
  326. Sets a CTE Timer for expiration.
  327. Arguments:
  328. Timer - Pointer to a CTE Timer variable.
  329. DueTime - Time in milliseconds after which the timer should expire.
  330. Handler - Timer expiration handler routine.
  331. Context - Argument to pass to the handler.
  332. Return Value:
  333. 0 if the timer could not be set. Nonzero otherwise.
  334. --*/
  335. {
  336. LARGE_INTEGER LargeDueTime;
  337. ASSERT(Handler != NULL);
  338. //
  339. // Convert milliseconds to hundreds of nanoseconds and negate to make
  340. // an NT relative timeout.
  341. //
  342. LargeDueTime.HighPart = 0;
  343. LargeDueTime.LowPart = DueTime;
  344. LargeDueTime = CTEConvertMillisecondsTo100ns(LargeDueTime);
  345. LargeDueTime.QuadPart = -LargeDueTime.QuadPart;
  346. Timer->t_handler = Handler;
  347. Timer->t_arg = Context;
  348. KeSetTimer(
  349. &(Timer->t_timer),
  350. LargeDueTime,
  351. &(Timer->t_dpc)
  352. );
  353. return((void *) 1);
  354. }
  355. unsigned long
  356. CTESystemUpTime(
  357. void
  358. )
  359. /*++
  360. Routine Description:
  361. Provides the time since system boot in milliseconds.
  362. Arguments:
  363. None.
  364. Return Value:
  365. The time since boot in milliseconds.
  366. --*/
  367. {
  368. LARGE_INTEGER TickCount;
  369. //
  370. // Get tick count and convert to hundreds of nanoseconds.
  371. //
  372. #pragma warning(push)
  373. #pragma warning(disable:4127) // condition expression constant
  374. KeQueryTickCount(&TickCount);
  375. #pragma warning(pop)
  376. TickCount = RtlExtendedIntegerMultiply(
  377. TickCount,
  378. (LONG) CTEpTimeIncrement
  379. );
  380. TickCount = CTEConvert100nsToMilliseconds(TickCount);
  381. return(TickCount.LowPart);
  382. }
  383. uint
  384. CTEBlock(
  385. IN CTEBlockStruc *BlockEvent
  386. )
  387. {
  388. NTSTATUS Status;
  389. Status = KeWaitForSingleObject(
  390. &(BlockEvent->cbs_event),
  391. UserRequest,
  392. KernelMode,
  393. FALSE,
  394. NULL
  395. );
  396. if (!NT_SUCCESS(Status)) {
  397. BlockEvent->cbs_status = Status;
  398. }
  399. return(BlockEvent->cbs_status);
  400. }
  401. uint
  402. CTEBlockWithTracker(
  403. IN CTEBlockStruc *BlockEvent,
  404. IN CTEBlockTracker *BlockTracker,
  405. IN void *Context
  406. )
  407. {
  408. uint Status;
  409. CTEInsertBlockTracker(BlockTracker, Context);
  410. Status = CTEBlock(BlockEvent);
  411. CTERemoveBlockTracker(BlockTracker);
  412. return Status;
  413. }
  414. void
  415. CTEInsertBlockTracker(
  416. IN CTEBlockTracker *BlockTracker,
  417. IN void *Context
  418. )
  419. {
  420. KIRQL OldIrql;
  421. BlockTracker->cbt_thread = KeGetCurrentThread();
  422. BlockTracker->cbt_context = Context;
  423. KeAcquireSpinLock(&CTEBlockSpinLock, &OldIrql);
  424. InsertTailList(&CTEBlockListHead, &BlockTracker->cbt_link);
  425. KeReleaseSpinLock(&CTEBlockSpinLock, OldIrql);
  426. }
  427. void
  428. CTERemoveBlockTracker(
  429. IN CTEBlockTracker *BlockTracker
  430. )
  431. {
  432. KIRQL OldIrql;
  433. KeAcquireSpinLock(&CTEBlockSpinLock, &OldIrql);
  434. RemoveEntryList(&BlockTracker->cbt_link);
  435. KeReleaseSpinLock(&CTEBlockSpinLock, OldIrql);
  436. }
  437. void
  438. CTESignal(
  439. IN CTEBlockStruc *BlockEvent,
  440. IN uint Status
  441. )
  442. {
  443. BlockEvent->cbs_status = Status;
  444. KeSetEvent(&(BlockEvent->cbs_event), 0, FALSE);
  445. return;
  446. }
  447. BOOLEAN
  448. CTEInitString(
  449. IN OUT PNDIS_STRING DestinationString,
  450. IN char *SourceString
  451. )
  452. /*++
  453. Routine Description:
  454. Converts a C style ASCII string to an NDIS_STRING. Resources needed for
  455. the NDIS_STRING are allocated and must be freed by a call to
  456. CTEFreeString.
  457. Arguments:
  458. DestinationString - A pointer to an NDIS_STRING variable with no
  459. associated data buffer.
  460. SourceString - The C style ASCII string source.
  461. Return Value:
  462. TRUE if the initialization succeeded. FALSE otherwise.
  463. --*/
  464. {
  465. STRING AnsiString;
  466. ULONG UnicodeLength;
  467. RtlInitString(&AnsiString, SourceString);
  468. // calculate size of unicoded ansi string + 2 for NULL terminator
  469. UnicodeLength = RtlAnsiStringToUnicodeSize(&AnsiString) + 2;
  470. // allocate storage for the unicode string
  471. DestinationString->Buffer = ExAllocatePool(NonPagedPool, UnicodeLength);
  472. if (DestinationString->Buffer == NULL) {
  473. DestinationString->MaximumLength = 0;
  474. return(FALSE);
  475. }
  476. DestinationString->MaximumLength = (USHORT) UnicodeLength;
  477. // Finally, convert the string to unicode
  478. RtlAnsiStringToUnicodeString(DestinationString, &AnsiString, FALSE);
  479. return(TRUE);
  480. }
  481. BOOLEAN
  482. CTEAllocateString(
  483. PNDIS_STRING String,
  484. unsigned short MaximumLength
  485. )
  486. /*++
  487. Routine Description:
  488. Allocates a data buffer for Length characters in an uninitialized
  489. NDIS_STRING. The allocated space must be freed by a call to CTEFreeString.
  490. Arguments:
  491. String - A pointer to an NDIS_STRING variable with no
  492. associated data buffer.
  493. Length - The maximum length of the string. In Unicode, this is a
  494. byte count.
  495. Return Value:
  496. TRUE if the initialization succeeded. FALSE otherwise.
  497. --*/
  498. {
  499. String->Buffer = ExAllocatePool(
  500. NonPagedPool,
  501. MaximumLength + sizeof(UNICODE_NULL)
  502. );
  503. if (String->Buffer == NULL) {
  504. return(FALSE);
  505. }
  506. String->Length = 0;
  507. String->MaximumLength = MaximumLength + sizeof(UNICODE_NULL);
  508. return(TRUE);
  509. }
  510. LONG
  511. CTELogEvent(
  512. IN PVOID LoggerId,
  513. IN ULONG EventCode,
  514. IN ULONG UniqueEventValue,
  515. IN USHORT NumStrings,
  516. IN PVOID StringsList, OPTIONAL
  517. IN ULONG DataSize,
  518. IN PVOID Data OPTIONAL
  519. )
  520. /*++
  521. Routine Description:
  522. This function allocates an I/O error log record, fills it in and writes it
  523. to the I/O error log.
  524. Arguments:
  525. LoggerId - Pointer to the driver object logging this event.
  526. EventCode - Identifies the error message.
  527. UniqueEventValue - Identifies this instance of a given error message.
  528. NumStrings - Number of unicode strings in strings list.
  529. DataSize - Number of bytes of data.
  530. Strings - Array of pointers to unicode strings (PWCHAR).
  531. Data - Binary dump data for this message, each piece being
  532. aligned on word boundaries.
  533. Return Value:
  534. TDI_SUCCESS - The error was successfully logged.
  535. TDI_BUFFER_TOO_SMALL - The error data was too large to be logged.
  536. TDI_NO_RESOURCES - Unable to allocate memory.
  537. Notes:
  538. This code is paged and may not be called at raised IRQL.
  539. --*/
  540. {
  541. PIO_ERROR_LOG_PACKET ErrorLogEntry;
  542. ULONG PaddedDataSize;
  543. ULONG PacketSize;
  544. ULONG TotalStringsSize = 0;
  545. USHORT i;
  546. PWCHAR *Strings;
  547. PWCHAR Tmp;
  548. PAGED_CODE();
  549. Strings = (PWCHAR *) StringsList;
  550. //
  551. // Sum up the length of the strings
  552. //
  553. for (i=0; i<NumStrings; i++) {
  554. PWCHAR currentString;
  555. ULONG stringSize;
  556. stringSize = sizeof(UNICODE_NULL);
  557. currentString = Strings[i];
  558. while (*currentString++ != UNICODE_NULL) {
  559. stringSize += sizeof(WCHAR);
  560. }
  561. TotalStringsSize += stringSize;
  562. }
  563. if (DataSize % sizeof(ULONG)) {
  564. PaddedDataSize = DataSize +
  565. (sizeof(ULONG) - (DataSize % sizeof(ULONG)));
  566. }
  567. else {
  568. PaddedDataSize = DataSize;
  569. }
  570. PacketSize = TotalStringsSize + PaddedDataSize;
  571. if (PacketSize > CTE_MAX_EVENT_LOG_DATA_SIZE) {
  572. return(TDI_BUFFER_TOO_SMALL); // Too much error data
  573. }
  574. //
  575. // Now add in the size of the log packet, but subtract 4 from the data
  576. // since the packet struct contains a ULONG for data.
  577. //
  578. if (PacketSize > sizeof(ULONG)) {
  579. PacketSize += sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
  580. }
  581. else {
  582. PacketSize += sizeof(IO_ERROR_LOG_PACKET);
  583. }
  584. ASSERT(PacketSize <= ERROR_LOG_MAXIMUM_SIZE);
  585. ErrorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
  586. (PDRIVER_OBJECT) LoggerId,
  587. (UCHAR) PacketSize
  588. );
  589. if (ErrorLogEntry == NULL) {
  590. return(TDI_NO_RESOURCES);
  591. }
  592. //
  593. // Fill in the necessary log packet fields.
  594. //
  595. ErrorLogEntry->UniqueErrorValue = UniqueEventValue;
  596. ErrorLogEntry->ErrorCode = EventCode;
  597. ErrorLogEntry->NumberOfStrings = NumStrings;
  598. ErrorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) +
  599. (USHORT) PaddedDataSize - sizeof(ULONG);
  600. ErrorLogEntry->DumpDataSize = (USHORT) PaddedDataSize;
  601. //
  602. // Copy the Dump Data to the packet
  603. //
  604. if (DataSize > 0) {
  605. RtlMoveMemory(
  606. (PVOID) ErrorLogEntry->DumpData,
  607. Data,
  608. DataSize
  609. );
  610. }
  611. //
  612. // Copy the strings to the packet.
  613. //
  614. Tmp = (PWCHAR) ((char *) ErrorLogEntry +
  615. ErrorLogEntry->StringOffset +
  616. PaddedDataSize);
  617. for (i=0; i<NumStrings; i++) {
  618. PWCHAR wchPtr = Strings[i];
  619. while( (*Tmp++ = *wchPtr++) != UNICODE_NULL);
  620. }
  621. IoWriteErrorLogEntry(ErrorLogEntry);
  622. return(TDI_SUCCESS);
  623. }