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.

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