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.

3360 lines
99 KiB

  1. /****************************************************************************/
  2. // stack.c
  3. //
  4. // Routines for managing Terminal Server driver stacks.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #include <ntimage.h>
  11. #include <minmax.h>
  12. #include <regapi.h>
  13. /*
  14. * Prototypes for procedures
  15. */
  16. NTSTATUS
  17. IcaDeviceControlStack (
  18. IN PICA_STACK pStack,
  19. IN PIRP Irp,
  20. IN PIO_STACK_LOCATION IrpSp
  21. );
  22. NTSTATUS
  23. IcaCleanupStack (
  24. IN PICA_STACK pStack,
  25. IN PIRP Irp,
  26. IN PIO_STACK_LOCATION IrpSp
  27. );
  28. NTSTATUS
  29. IcaCloseStack (
  30. IN PICA_STACK pStack,
  31. IN PIRP Irp,
  32. IN PIO_STACK_LOCATION IrpSp
  33. );
  34. /*
  35. * Local procedure prototypes
  36. */
  37. NTSTATUS
  38. _LogError(
  39. IN PDEVICE_OBJECT pDeviceObject,
  40. IN NTSTATUS Status,
  41. IN LPWSTR * pArgStrings,
  42. IN ULONG ArgStringCount,
  43. IN PVOID pRawData,
  44. IN ULONG RawDataLength
  45. );
  46. NTSTATUS
  47. _IcaDriverThread(
  48. IN PVOID pData
  49. );
  50. PICA_STACK
  51. _IcaAllocateStack(
  52. VOID
  53. );
  54. VOID
  55. _IcaFreeStack(
  56. PICA_STACK pStack
  57. );
  58. NTSTATUS
  59. _IcaPushStack(
  60. IN PICA_STACK pStack,
  61. IN PICA_STACK_PUSH pStackPush
  62. );
  63. NTSTATUS
  64. _IcaPopStack(
  65. IN PICA_STACK pStack
  66. );
  67. NTSTATUS
  68. _IcaCallStack(
  69. IN PICA_STACK pStack,
  70. IN ULONG ProcIndex,
  71. IN OUT PVOID pParms
  72. );
  73. NTSTATUS
  74. _IcaCallStackNoLock(
  75. IN PICA_STACK pStack,
  76. IN ULONG ProcIndex,
  77. IN OUT PVOID pParms
  78. );
  79. NTSTATUS
  80. _IcaLoadSd(
  81. IN PDLLNAME SdName,
  82. OUT PSDLINK *ppSdLink
  83. );
  84. NTSTATUS
  85. _IcaUnloadSd(
  86. IN PSDLINK pSdLink
  87. );
  88. NTSTATUS
  89. _IcaCallSd(
  90. IN PSDLINK pSdLink,
  91. IN ULONG ProcIndex,
  92. IN PVOID pParms
  93. );
  94. VOID
  95. _IcaReferenceSdLoad(
  96. IN PSDLOAD pSdLoad
  97. );
  98. VOID
  99. _IcaDereferenceSdLoad(
  100. IN PSDLOAD pSdLoad
  101. );
  102. NTSTATUS
  103. _IcaLoadSdWorker(
  104. IN PDLLNAME SdName,
  105. OUT PSDLOAD *ppSdLoad
  106. );
  107. NTSTATUS
  108. _IcaUnloadSdWorker(
  109. IN PSDLOAD pSdLoad
  110. );
  111. NTSTATUS
  112. IcaExceptionFilter(
  113. IN PWSTR OutputString,
  114. IN PEXCEPTION_POINTERS pexi
  115. );
  116. NTSTATUS
  117. _RegisterBrokenEvent(
  118. IN PICA_STACK pStack,
  119. IN PICA_STACK_BROKEN pStackBroken
  120. );
  121. NTSTATUS
  122. _EnablePassthru( PICA_STACK pStack );
  123. NTSTATUS
  124. _DisablePassthru( PICA_STACK pStack );
  125. NTSTATUS
  126. _ReconnectStack( PICA_STACK pStack, HANDLE hIca );
  127. NTSTATUS
  128. IcaBindVirtualChannels(
  129. IN PICA_STACK pStack
  130. );
  131. VOID
  132. IcaRebindVirtualChannels(
  133. IN PICA_CONNECTION pConnect
  134. );
  135. VOID
  136. IcaUnbindVirtualChannels(
  137. IN PICA_CONNECTION pConnect
  138. );
  139. VOID
  140. IcaFreeAllVcBind(
  141. IN PICA_CONNECTION pConnect
  142. );
  143. /*
  144. * Buffer Allocation counters.
  145. */
  146. ULONG gAllocSucceed;
  147. ULONG gAllocFailed;
  148. ULONG gAllocFreed;
  149. extern HANDLE g_TermServProcessID;
  150. ULONG g_KeepAliveInterval=0;
  151. /*
  152. * Dispatch table for stack objects
  153. */
  154. PICA_DISPATCH IcaStackDispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1] = {
  155. NULL, // IRP_MJ_CREATE
  156. NULL, // IRP_MJ_CREATE_NAMED_PIPE
  157. IcaCloseStack, // IRP_MJ_CLOSE
  158. NULL, // IRP_MJ_READ
  159. NULL, // IRP_MJ_WRITE
  160. NULL, // IRP_MJ_QUERY_INFORMATION
  161. NULL, // IRP_MJ_SET_INFORMATION
  162. NULL, // IRP_MJ_QUERY_EA
  163. NULL, // IRP_MJ_SET_EA
  164. NULL, // IRP_MJ_FLUSH_BUFFERS
  165. NULL, // IRP_MJ_QUERY_VOLUME_INFORMATION
  166. NULL, // IRP_MJ_SET_VOLUME_INFORMATION
  167. NULL, // IRP_MJ_DIRECTORY_CONTROL
  168. NULL, // IRP_MJ_FILE_SYSTEM_CONTROL
  169. IcaDeviceControlStack, // IRP_MJ_DEVICE_CONTROL
  170. NULL, // IRP_MJ_INTERNAL_DEVICE_CONTROL
  171. NULL, // IRP_MJ_SHUTDOWN
  172. NULL, // IRP_MJ_LOCK_CONTROL
  173. IcaCleanupStack, // IRP_MJ_CLEANUP
  174. NULL, // IRP_MJ_CREATE_MAILSLOT
  175. NULL, // IRP_MJ_QUERY_SECURITY
  176. NULL, // IRP_MJ_SET_SECURITY
  177. NULL, // IRP_MJ_SET_POWER
  178. NULL, // IRP_MJ_QUERY_POWER
  179. };
  180. NTSTATUS
  181. IcaCreateStack (
  182. IN PICA_CONNECTION pConnect,
  183. IN PICA_OPEN_PACKET openPacket,
  184. IN PIRP Irp,
  185. IN PIO_STACK_LOCATION IrpSp
  186. )
  187. /*++
  188. Routine Description:
  189. This routine is called to create a new ICA_STACK objecte.
  190. Arguments:
  191. pConnect -- pointer to ICA_CONNECTION object
  192. Irp - Pointer to I/O request packet
  193. IrpSp - pointer to the stack location to use for this request.
  194. Return Value:
  195. NTSTATUS -- Indicates whether the request was successfully queued.
  196. --*/
  197. {
  198. PLIST_ENTRY Head, Next;
  199. PICA_STACK pStack;
  200. KIRQL OldIrql;
  201. LONG PrimaryCount, ShadowCount, PassthruCount, ConsoleCount;
  202. NTSTATUS Status;
  203. PICA_STACK pPrimaryStack = NULL;
  204. /*
  205. * Allocate a new ICA stack object
  206. */
  207. pStack = _IcaAllocateStack();
  208. if ( pStack == NULL )
  209. return( STATUS_INSUFFICIENT_RESOURCES );
  210. /*
  211. * Finish initializing the stack object
  212. * (non-primary stacks are initialized with the fIoDisabled
  213. * flag set to TRUE, i.e. they must be manually enabled)
  214. */
  215. pStack->StackClass = openPacket->TypeInfo.StackClass;
  216. pStack->fIoDisabled = ((pStack->StackClass != Stack_Primary) &&
  217. (pStack->StackClass != Stack_Console));
  218. /*
  219. * Lock connection object while creating new stack
  220. */
  221. IcaLockConnection( pConnect );
  222. /*
  223. * Reference the connection object this stack belongs to.
  224. */
  225. IcaReferenceConnection( pConnect );
  226. pStack->pConnect = (PUCHAR)pConnect;
  227. /*
  228. * Search the existing stacks to check for invalid combinations.
  229. * 1) there can be only 1 primary stack per connection,
  230. * 2) there can be multiple shadow stacks per connection,
  231. * but ONLY if there is no passthru stack,
  232. * 3) there can be only 1 passthru stack per connection,
  233. * but only if there is an existing primary stack AND no shadow stacks.
  234. * 4) there can be only 1 console stack
  235. */
  236. Head = &pConnect->StackHead;
  237. PrimaryCount = ShadowCount = PassthruCount = ConsoleCount = 0;
  238. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  239. PICA_STACK pCurrentStack;
  240. pCurrentStack = CONTAINING_RECORD( Next, ICA_STACK, StackEntry );
  241. switch ( pCurrentStack->StackClass ) {
  242. case Stack_Primary :
  243. PrimaryCount++;
  244. if( pStack->StackClass == Stack_Passthru) {
  245. // store the primary stack pointer for
  246. // passthru setup
  247. pPrimaryStack = pCurrentStack;
  248. }
  249. ASSERT(PrimaryCount == 1);
  250. break;
  251. case Stack_Shadow :
  252. ShadowCount++;
  253. break;
  254. case Stack_Passthru :
  255. PassthruCount++;
  256. ASSERT(PassthruCount == 1);
  257. break;
  258. case Stack_Console :
  259. ConsoleCount++;
  260. ASSERT(ConsoleCount == 1);
  261. break;
  262. }
  263. }
  264. Status = STATUS_SUCCESS;
  265. switch ( pStack->StackClass ) {
  266. case Stack_Primary :
  267. if ( PrimaryCount != 0 )
  268. Status = STATUS_INVALID_PARAMETER;
  269. break;
  270. case Stack_Shadow :
  271. if ( PassthruCount != 0 )
  272. Status = STATUS_INVALID_PARAMETER;
  273. break;
  274. case Stack_Passthru :
  275. if ( PassthruCount != 0 || PrimaryCount != 1 || ShadowCount != 0 )
  276. Status = STATUS_INVALID_PARAMETER;
  277. else {
  278. /*
  279. * Put the stack pointers in place.
  280. * This will make sure that we don't end up in a
  281. * a race condition and drop some pdus before the
  282. * shadow sequence completes.
  283. */
  284. // PrimaryCount is 1 so pPrimaryStack is valid
  285. ASSERT(pPrimaryStack);
  286. pPrimaryStack->pPassthru = pStack;
  287. pStack->pPassthru = pPrimaryStack;
  288. }
  289. break;
  290. case Stack_Console :
  291. if ( ConsoleCount != 0 )
  292. Status = STATUS_INVALID_PARAMETER;
  293. break;
  294. }
  295. if ( Status != STATUS_SUCCESS ) {
  296. IcaUnlockConnection( pConnect );
  297. pStack->RefCount = 0;
  298. _IcaFreeStack( pStack );
  299. TRACE(( pConnect, TC_ICADD, TT_ERROR, "TermDD: IcaCreateStack failed, 0x%x\n", Status ));
  300. return( Status );
  301. }
  302. /*
  303. * Link this stack into the connection object stack list.
  304. */
  305. if (( pStack->StackClass == Stack_Primary ) ||
  306. ( pStack->StackClass == Stack_Console )) {
  307. InsertHeadList( &pConnect->StackHead, &pStack->StackEntry );
  308. } else {
  309. InsertTailList( &pConnect->StackHead, &pStack->StackEntry );
  310. }
  311. /*
  312. * Unlock connection object now
  313. */
  314. IcaUnlockConnection( pConnect );
  315. /*
  316. * Initialize the LastKeepAliveTime field to current system time
  317. */
  318. KeQuerySystemTime(&pStack->LastKeepAliveTime);
  319. /*
  320. * Lock the stack list for updating
  321. */
  322. IcaAcquireSpinLock(&IcaStackListSpinLock, &OldIrql);
  323. /*
  324. * Insert the stack to the stack list, increment total number of stacks
  325. */
  326. InsertTailList(IcaNextStack, &pStack->StackNode);
  327. IcaTotalNumOfStacks++;
  328. /*
  329. * Unlock the stack list now
  330. */
  331. IcaReleaseSpinLock(&IcaStackListSpinLock, OldIrql);
  332. /*
  333. * Save a pointer to the stack in the file object
  334. * so that we can find it in future calls.
  335. */
  336. IrpSp->FileObject->FsContext = pStack;
  337. IcaDereferenceStack( pStack );
  338. TRACE(( pConnect, TC_ICADD, TT_API1, "TermDD: IcaCreateStack, success\n" ));
  339. return( STATUS_SUCCESS );
  340. }
  341. NTSTATUS
  342. IcaDeviceControlStack(
  343. IN PICA_STACK pStack,
  344. IN PIRP Irp,
  345. IN PIO_STACK_LOCATION IrpSp
  346. )
  347. {
  348. PICA_CONNECTION pConnect;
  349. PICA_TRACE_BUFFER pTraceBuffer;
  350. PICA_STACK_RECONNECT pStackReconnect;
  351. SD_IOCTL SdIoctl;
  352. NTSTATUS Status;
  353. ULONG code;
  354. LARGE_INTEGER WaitTimeout;
  355. PLARGE_INTEGER pWaitTimeout = NULL;
  356. BYTE *Buffer = NULL;
  357. /*
  358. * Extract the IOCTL control code and process the request.
  359. */
  360. code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  361. #if DBG
  362. if ( code != IOCTL_ICA_STACK_TRACE ) {
  363. IcaLockStack( pStack );
  364. TRACESTACK(( pStack, TC_ICADD, TT_API2, "TermDD: IcaDeviceControlStack, fc %d (enter)\n",
  365. (code & 0x3fff) >> 2 ));
  366. IcaUnlockStack( pStack );
  367. }
  368. #endif
  369. try {
  370. switch ( code ) {
  371. case IOCTL_ICA_STACK_PUSH :
  372. {
  373. ICA_STACK_PUSH StackPush;
  374. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_STACK_PUSH) )
  375. return( STATUS_BUFFER_TOO_SMALL );
  376. if ( Irp->RequestorMode != KernelMode ) {
  377. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  378. sizeof(ICA_STACK_PUSH),
  379. sizeof(BYTE) );
  380. }
  381. // This IOCTL should only be invoked if we are called from system process
  382. // If not, we deny the request
  383. if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) {
  384. return (STATUS_ACCESS_DENIED);
  385. }
  386. memcpy(&StackPush, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  387. sizeof(ICA_STACK_PUSH));
  388. Status = _IcaPushStack( pStack, &StackPush );
  389. break;
  390. }
  391. case IOCTL_ICA_STACK_POP :
  392. IcaLockConnectionForStack( pStack );
  393. Status = _IcaPopStack( pStack );
  394. IcaUnlockConnectionForStack( pStack );
  395. break;
  396. case IOCTL_ICA_STACK_QUERY_STATUS :
  397. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(pStack->ProtocolStatus) )
  398. return( STATUS_BUFFER_TOO_SMALL );
  399. if ( Irp->RequestorMode != KernelMode ) {
  400. ProbeForWrite( Irp->UserBuffer,
  401. sizeof(pStack->ProtocolStatus),
  402. sizeof(BYTE) );
  403. }
  404. RtlCopyMemory( Irp->UserBuffer,
  405. &pStack->ProtocolStatus,
  406. sizeof(pStack->ProtocolStatus) );
  407. Irp->IoStatus.Information = sizeof(pStack->ProtocolStatus);
  408. Status = STATUS_SUCCESS;
  409. break;
  410. case IOCTL_ICA_STACK_QUERY_CLIENT :
  411. if ( Irp->RequestorMode != KernelMode ) {
  412. ProbeForWrite( Irp->UserBuffer,
  413. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  414. sizeof(BYTE) );
  415. }
  416. SdIoctl.IoControlCode = code;
  417. SdIoctl.InputBuffer = NULL;
  418. SdIoctl.InputBufferLength = 0;
  419. SdIoctl.OutputBuffer = Irp->UserBuffer;
  420. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  421. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  422. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  423. break;
  424. case IOCTL_ICA_STACK_QUERY_CLIENT_EXTENDED :
  425. if ( Irp->RequestorMode != KernelMode ) {
  426. ProbeForWrite( Irp->UserBuffer,
  427. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  428. sizeof(BYTE) );
  429. }
  430. SdIoctl.IoControlCode = code;
  431. SdIoctl.InputBuffer = NULL;
  432. SdIoctl.InputBufferLength = 0;
  433. SdIoctl.OutputBuffer = Irp->UserBuffer;
  434. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  435. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  436. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  437. break;
  438. case IOCTL_ICA_STACK_QUERY_AUTORECONNECT :
  439. if ( Irp->RequestorMode != KernelMode ) {
  440. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  441. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  442. sizeof(BYTE) );
  443. ProbeForWrite( Irp->UserBuffer,
  444. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  445. sizeof(BYTE) );
  446. }
  447. SdIoctl.IoControlCode = code;
  448. SdIoctl.InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  449. SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  450. SdIoctl.OutputBuffer = Irp->UserBuffer;
  451. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  452. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  453. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  454. break;
  455. case IOCTL_ICA_STACK_QUERY_MODULE_DATA :
  456. if ( Irp->RequestorMode != KernelMode ) {
  457. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  458. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  459. sizeof(BYTE) );
  460. ProbeForWrite( Irp->UserBuffer,
  461. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  462. sizeof(BYTE) );
  463. }
  464. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength) {
  465. Buffer = ICA_ALLOCATE_POOL( NonPagedPool,
  466. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  467. if (Buffer) {
  468. memcpy(Buffer, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  469. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  470. }
  471. else {
  472. Status = STATUS_NO_MEMORY;
  473. break;
  474. }
  475. }
  476. SdIoctl.IoControlCode = code;
  477. SdIoctl.InputBuffer = Buffer;
  478. SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  479. SdIoctl.OutputBuffer = Irp->UserBuffer;
  480. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  481. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  482. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  483. /* this is so IoStatus.Information gets returned to the caller */
  484. if (Status == STATUS_BUFFER_TOO_SMALL)
  485. Status = STATUS_BUFFER_OVERFLOW;
  486. break;
  487. case IOCTL_ICA_STACK_QUERY_LAST_INPUT_TIME :
  488. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ICA_STACK_LAST_INPUT_TIME) )
  489. return( STATUS_BUFFER_TOO_SMALL );
  490. if ( Irp->RequestorMode != KernelMode ) {
  491. ProbeForWrite( Irp->UserBuffer,
  492. sizeof(ICA_STACK_LAST_INPUT_TIME),
  493. sizeof(BYTE) );
  494. }
  495. ((PICA_STACK_LAST_INPUT_TIME)Irp->UserBuffer)->LastInputTime = pStack->LastInputTime;
  496. Irp->IoStatus.Information = sizeof(ICA_STACK_LAST_INPUT_TIME);
  497. Status = STATUS_SUCCESS;
  498. break;
  499. case IOCTL_ICA_STACK_TRACE :
  500. {
  501. unsigned DataLen = 0;
  502. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)FIELD_OFFSET(ICA_TRACE_BUFFER,Data[0]) )
  503. return( STATUS_BUFFER_TOO_SMALL );
  504. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength > sizeof(ICA_TRACE_BUFFER) )
  505. return( STATUS_INVALID_BUFFER_SIZE );
  506. if ( Irp->RequestorMode != KernelMode ) {
  507. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  508. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  509. sizeof(BYTE) );
  510. }
  511. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength) {
  512. Buffer = ICA_ALLOCATE_POOL( NonPagedPool,
  513. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  514. if (Buffer) {
  515. memcpy(Buffer, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  516. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  517. }
  518. else {
  519. Status = STATUS_NO_MEMORY;
  520. break;
  521. }
  522. }
  523. pTraceBuffer = (PICA_TRACE_BUFFER)Buffer;
  524. // Make sure the trace buffer is NULL terminated
  525. DataLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength -
  526. FIELD_OFFSET(ICA_TRACE_BUFFER, Data);
  527. if (pTraceBuffer->Data[DataLen - 1] == 0) {
  528. pConnect = IcaLockConnectionForStack( pStack );
  529. IcaTraceFormat( &pConnect->TraceInfo,
  530. pTraceBuffer->TraceClass,
  531. pTraceBuffer->TraceEnable,
  532. pTraceBuffer->Data );
  533. IcaUnlockConnectionForStack( pStack );
  534. Status = STATUS_SUCCESS;
  535. }
  536. else {
  537. Status = STATUS_BUFFER_OVERFLOW;
  538. }
  539. break;
  540. }
  541. case IOCTL_ICA_STACK_REGISTER_BROKEN :
  542. {
  543. ICA_STACK_BROKEN BrokenEvent;
  544. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_STACK_BROKEN) )
  545. return( STATUS_BUFFER_TOO_SMALL );
  546. if ( Irp->RequestorMode != KernelMode ) {
  547. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  548. sizeof(ICA_STACK_BROKEN),
  549. sizeof(BYTE) );
  550. }
  551. memcpy(&BrokenEvent, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  552. sizeof(ICA_STACK_BROKEN));
  553. Status = _RegisterBrokenEvent( pStack,
  554. &BrokenEvent );
  555. break;
  556. }
  557. case IOCTL_ICA_STACK_ENABLE_IO :
  558. pStack->fIoDisabled = FALSE;
  559. /* If enabling the passthru stack, then enable passthru mode */
  560. if ( pStack->StackClass == Stack_Passthru ) {
  561. Status = _EnablePassthru( pStack );
  562. } else {
  563. Status = STATUS_SUCCESS;
  564. }
  565. break;
  566. case IOCTL_ICA_STACK_DISABLE_IO :
  567. pStack->fIoDisabled = TRUE;
  568. /* If disabling the passthru stack, then disable passthru mode */
  569. if ( pStack->StackClass == Stack_Passthru ) {
  570. Status = _DisablePassthru( pStack );
  571. IcaLockStack( pStack );
  572. // Now wait for any input still in progress to end.
  573. if ( pStack->fDoingInput ) {
  574. NTSTATUS WaitStatus;
  575. pStack->fDisablingIo = TRUE;
  576. KeClearEvent( &pStack->IoEndEvent );
  577. IcaUnlockStack( pStack );
  578. //
  579. // Convert the timeout to a relative system time value and wait.
  580. //
  581. WaitTimeout = RtlEnlargedIntegerMultiply( 60000, -10000 );
  582. pWaitTimeout = &WaitTimeout;
  583. WaitStatus = KeWaitForSingleObject( &pStack->IoEndEvent,
  584. UserRequest, UserMode, FALSE, pWaitTimeout );
  585. #if DBG
  586. if ( WaitStatus != STATUS_SUCCESS ) {
  587. DbgPrint("TermDD: IOCTL_ICA_STACK_DISABLE_IO: WaitStatus=%x\n", WaitStatus);
  588. ASSERT(WaitStatus == STATUS_SUCCESS);
  589. }
  590. #endif
  591. IcaLockStack( pStack );
  592. pStack->fDisablingIo = FALSE;
  593. }
  594. IcaUnlockStack( pStack );
  595. } else {
  596. Status = STATUS_SUCCESS;
  597. }
  598. break;
  599. case IOCTL_ICA_STACK_DISCONNECT :
  600. {
  601. HANDLE hIca;
  602. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_STACK_RECONNECT) )
  603. return( STATUS_BUFFER_TOO_SMALL );
  604. if ( Irp->RequestorMode != KernelMode ) {
  605. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  606. sizeof(ICA_STACK_RECONNECT),
  607. sizeof(BYTE) );
  608. }
  609. pStackReconnect = (PICA_STACK_RECONNECT)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  610. hIca = pStackReconnect->hIca;
  611. /*
  612. * Notify stack drivers of disconnect
  613. */
  614. SdIoctl.IoControlCode = code;
  615. SdIoctl.InputBuffer = NULL;
  616. SdIoctl.InputBufferLength = 0;
  617. SdIoctl.OutputBuffer = NULL;
  618. SdIoctl.OutputBufferLength = 0;
  619. (void)_IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  620. /*
  621. * Disconnect stack
  622. */
  623. Status = _ReconnectStack( pStack, hIca );
  624. break;
  625. }
  626. case IOCTL_ICA_STACK_RECONNECT :
  627. {
  628. ICA_STACK_RECONNECT StackReconnect;
  629. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_STACK_RECONNECT) )
  630. return( STATUS_BUFFER_TOO_SMALL );
  631. if ( Irp->RequestorMode != KernelMode ) {
  632. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  633. sizeof(ICA_STACK_RECONNECT),
  634. sizeof(BYTE) );
  635. }
  636. /*
  637. * Reconnect stack
  638. */
  639. memcpy(&StackReconnect, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  640. sizeof(ICA_STACK_RECONNECT));
  641. Status = _ReconnectStack( pStack, StackReconnect.hIca );
  642. /*
  643. * Notify stack drivers of reconnect
  644. */
  645. SdIoctl.IoControlCode = code;
  646. SdIoctl.InputBuffer = &StackReconnect;
  647. SdIoctl.InputBufferLength = sizeof(ICA_STACK_RECONNECT);
  648. SdIoctl.OutputBuffer = NULL;
  649. SdIoctl.OutputBufferLength = 0;
  650. (void)_IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  651. break;
  652. }
  653. case IOCTL_ICA_STACK_WAIT_FOR_ICA:
  654. if ( Irp->RequestorMode != KernelMode ) {
  655. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  656. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  657. sizeof(BYTE) );
  658. ProbeForWrite( Irp->UserBuffer,
  659. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  660. sizeof(BYTE) );
  661. }
  662. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength) {
  663. Buffer = ICA_ALLOCATE_POOL( NonPagedPool,
  664. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  665. if (Buffer) {
  666. memcpy(Buffer, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  667. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  668. }
  669. else {
  670. Status = STATUS_NO_MEMORY;
  671. break;
  672. }
  673. }
  674. SdIoctl.IoControlCode = code;
  675. SdIoctl.InputBuffer = Buffer;
  676. SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  677. SdIoctl.OutputBuffer = Irp->UserBuffer;
  678. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  679. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  680. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  681. if ( NT_SUCCESS(Status) ) {
  682. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: IcaDeviceControlStack: Binding vchannels\n"));
  683. Status = IcaBindVirtualChannels( pStack );
  684. }
  685. break;
  686. case IOCTL_ICA_STACK_CONSOLE_CONNECT:
  687. if ( Irp->RequestorMode != KernelMode ) {
  688. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  689. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  690. sizeof(BYTE) );
  691. ProbeForWrite( Irp->UserBuffer,
  692. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  693. sizeof(BYTE) );
  694. }
  695. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength) {
  696. Buffer = ICA_ALLOCATE_POOL( NonPagedPool,
  697. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  698. if (Buffer) {
  699. memcpy(Buffer, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  700. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  701. }
  702. else {
  703. Status = STATUS_NO_MEMORY;
  704. break;
  705. }
  706. }
  707. SdIoctl.IoControlCode = code;
  708. SdIoctl.InputBuffer = Buffer;
  709. SdIoctl.OutputBuffer = Irp->UserBuffer;
  710. SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  711. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  712. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  713. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  714. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: IcaDeviceControlStack: console connect\n"));
  715. if ( NT_SUCCESS(Status) ) {
  716. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: IcaDeviceControlStack: Binding vchannels\n"));
  717. Status = IcaBindVirtualChannels( pStack );
  718. }
  719. break;
  720. case IOCTL_ICA_STACK_CANCEL_IO :
  721. pStack->fClosing = TRUE;
  722. /* fall through */
  723. default:
  724. if ( Irp->RequestorMode != KernelMode ) {
  725. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  726. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  727. sizeof(BYTE) );
  728. ProbeForWrite( Irp->UserBuffer,
  729. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  730. sizeof(BYTE) );
  731. }
  732. SdIoctl.IoControlCode = code;
  733. SdIoctl.InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  734. SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  735. SdIoctl.OutputBuffer = Irp->UserBuffer;
  736. SdIoctl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  737. Status = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  738. Irp->IoStatus.Information = SdIoctl.BytesReturned;
  739. /* initialize virtual channel name bindings */
  740. if ( NT_SUCCESS(Status) && (code == IOCTL_ICA_STACK_CONNECTION_QUERY) ) {
  741. Status = IcaBindVirtualChannels( pStack );
  742. if ( Status == STATUS_SUCCESS ) {
  743. ICA_STACK_QUERY_BUFFER icaSQB;
  744. NTSTATUS QueryStatus;
  745. SdIoctl.IoControlCode = IOCTL_ICA_STACK_QUERY_BUFFER;
  746. SdIoctl.InputBuffer = NULL;
  747. SdIoctl.InputBufferLength = 0;
  748. SdIoctl.OutputBuffer = &icaSQB;
  749. SdIoctl.OutputBufferLength = sizeof(icaSQB);
  750. QueryStatus = _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  751. if ( NT_SUCCESS(QueryStatus) ) {
  752. pStack->OutBufCount = icaSQB.WdBufferCount;
  753. pStack->OutBufLength = icaSQB.TdBufferSize;
  754. }
  755. }
  756. }
  757. /* this is so IoStatus.Information gets returned to the caller */
  758. if ( Status == STATUS_BUFFER_TOO_SMALL )
  759. Status = STATUS_BUFFER_OVERFLOW;
  760. break;
  761. }
  762. } except( IcaExceptionFilter( L"IcaDeviceControlStack TRAPPED!!",
  763. GetExceptionInformation() ) ) {
  764. Status = GetExceptionCode();
  765. }
  766. if (Buffer) {
  767. ICA_FREE_POOL(Buffer);
  768. Buffer = NULL;
  769. }
  770. #if DBG
  771. if ( code != IOCTL_ICA_STACK_TRACE ) {
  772. IcaLockStack( pStack );
  773. TRACESTACK(( pStack, TC_ICADD, TT_API1, "TermDD: IcaDeviceControlStack, fc %d, 0x%x\n",
  774. (code & 0x3fff) >> 2, Status ));
  775. IcaUnlockStack( pStack );
  776. }
  777. #endif
  778. return( Status );
  779. }
  780. NTSTATUS
  781. IcaCleanupStack(
  782. IN PICA_STACK pStack,
  783. IN PIRP Irp,
  784. IN PIO_STACK_LOCATION IrpSp
  785. )
  786. {
  787. return( STATUS_SUCCESS );
  788. }
  789. NTSTATUS
  790. IcaCloseStack(
  791. IN PICA_STACK pStack,
  792. IN PIRP Irp,
  793. IN PIO_STACK_LOCATION IrpSp
  794. )
  795. {
  796. SD_IOCTL SdIoctl;
  797. PICA_CONNECTION pConnect;
  798. KIRQL OldIrql;
  799. #if DBG
  800. IcaLockStack( pStack );
  801. TRACESTACK(( pStack, TC_ICADD, TT_API1, "TermDD: IcaCloseStack (enter)\n" ));
  802. IcaUnlockStack( pStack );
  803. #endif
  804. /*
  805. * If passthru mode is enabled, disable it now.
  806. */
  807. if ( pStack->pPassthru ) {
  808. _DisablePassthru( pStack );
  809. }
  810. /*
  811. * Send cancel i/o to stack drivers
  812. */
  813. SdIoctl.IoControlCode = IOCTL_ICA_STACK_CANCEL_IO;
  814. (void) _IcaCallStack( pStack, SD$IOCTL, &SdIoctl );
  815. /*
  816. * Make sure all Stack Drivers are unloaded.
  817. */
  818. pConnect = IcaLockConnectionForStack( pStack );
  819. while ( _IcaPopStack( pStack ) == STATUS_SUCCESS )
  820. ;
  821. IcaUnlockConnection( pConnect );
  822. /*
  823. * Dereference the broken event if we have one
  824. */
  825. if ( pStack->pBrokenEventObject ) {
  826. KeSetEvent( pStack->pBrokenEventObject, 0, FALSE );
  827. ObDereferenceObject( pStack->pBrokenEventObject );
  828. pStack->pBrokenEventObject = NULL;
  829. }
  830. /*
  831. * If closing the primary stack, unbind the virtual channels.
  832. * Unlink this stack from the stack list for this connection.
  833. */
  834. pConnect = IcaLockConnectionForStack( pStack );
  835. if ( pStack->StackClass == Stack_Primary || pStack->StackClass == Stack_Console ) {
  836. IcaUnbindVirtualChannels( pConnect );
  837. IcaFreeAllVcBind( pConnect );
  838. }
  839. RemoveEntryList( &pStack->StackEntry );
  840. IcaUnlockConnection( pConnect );
  841. /*
  842. * Lock the stack list for update
  843. */
  844. IcaAcquireSpinLock(&IcaStackListSpinLock, &OldIrql);
  845. /*
  846. * Remove the stack from the stack list. Before doing so, check if IcaNextStack
  847. * is pointing to this stack, if so, move IcaNextStack to the next stack
  848. * in the list. Also, decrement total number of stacks
  849. */
  850. if (&pStack->StackNode == IcaNextStack) {
  851. IcaNextStack = pStack->StackNode.Flink;
  852. }
  853. RemoveEntryList(&pStack->StackNode);
  854. if (IcaTotalNumOfStacks != 0) {
  855. IcaTotalNumOfStacks--;
  856. }
  857. /*
  858. * Unlock the stack list now
  859. */
  860. IcaReleaseSpinLock(&IcaStackListSpinLock, OldIrql);
  861. /*
  862. * Remove the file object reference for this stack.
  863. * This will cause the stack to be deleted when all other
  864. * references are gone.
  865. */
  866. IcaDereferenceStack( pStack );
  867. return( STATUS_SUCCESS );
  868. }
  869. VOID
  870. IcaReferenceStack(
  871. IN PICA_STACK pStack
  872. )
  873. {
  874. ASSERT( pStack->RefCount >= 0 );
  875. /*
  876. * Increment the reference count
  877. */
  878. if ( InterlockedIncrement( &pStack->RefCount) <= 0 ) {
  879. ASSERT( FALSE );
  880. }
  881. }
  882. VOID
  883. IcaDereferenceStack(
  884. IN PICA_STACK pStack
  885. )
  886. {
  887. ASSERT( pStack->RefCount > 0 );
  888. /*
  889. * Decrement the reference count; if it is 0, free the stack.
  890. */
  891. if ( InterlockedDecrement( &pStack->RefCount) == 0 ) {
  892. _IcaFreeStack( pStack );
  893. }
  894. }
  895. PICA_CONNECTION
  896. IcaGetConnectionForStack(
  897. IN PICA_STACK pStack
  898. )
  899. {
  900. /*
  901. * As long as the stack object is locked, it's safe for us
  902. * to pick up the pConnect pointer and return it.
  903. * WARNING: Once the caller unlocks the stack object, the pointer
  904. * returned below must not be referenced anymore and may
  905. * no longer be valid.
  906. */
  907. ASSERT( ExIsResourceAcquiredExclusiveLite( &pStack->Resource ) );
  908. return( (PICA_CONNECTION)pStack->pConnect );
  909. }
  910. PICA_CONNECTION
  911. IcaLockConnectionForStack(
  912. IN PICA_STACK pStack
  913. )
  914. {
  915. PICA_CONNECTION pConnect;
  916. /*
  917. * Acquire the Reconnect resource lock so that the pConnect
  918. * pointer cannot change before we get the connection locked.
  919. */
  920. KeEnterCriticalRegion();
  921. ExAcquireResourceSharedLite( IcaReconnectResource, TRUE );
  922. pConnect = (PICA_CONNECTION)pStack->pConnect;
  923. IcaLockConnection( pConnect );
  924. ExReleaseResourceLite( IcaReconnectResource );
  925. KeLeaveCriticalRegion();
  926. return( pConnect );
  927. }
  928. VOID
  929. IcaUnlockConnectionForStack(
  930. IN PICA_STACK pStack
  931. )
  932. {
  933. PICA_CONNECTION pConnect;
  934. /*
  935. * As long as the connection object is locked, it's safe for us
  936. * to pick up the pConnect pointer from the stack and use it.
  937. */
  938. pConnect = (PICA_CONNECTION)pStack->pConnect;
  939. ASSERT( ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
  940. IcaUnlockConnection( pConnect );
  941. }
  942. /*******************************************************************************
  943. *
  944. * IcaCallDriver
  945. *
  946. * Call the topmost stack driver
  947. *
  948. * This is the main interface routine that all channels use
  949. * to call the stack driver(s).
  950. *
  951. * ENTRY:
  952. * pChannel (input)
  953. * pointer to channel object this call is from
  954. * ProcIndex (input)
  955. * index of driver proc to call
  956. * pParms (input)
  957. * pointer to driver parms
  958. *
  959. * EXIT:
  960. * STATUS_SUCCESS - no error
  961. *
  962. ******************************************************************************/
  963. NTSTATUS
  964. IcaCallDriver(
  965. IN PICA_CHANNEL pChannel,
  966. IN ULONG ProcIndex,
  967. IN PVOID pParms
  968. )
  969. {
  970. PLIST_ENTRY Head, Next;
  971. PICA_STACK pStack;
  972. NTSTATUS Status = STATUS_SUCCESS;
  973. TRACECHANNEL(( pChannel, TC_ICADD, TT_API4, "TermDD: IcaCallDriver, ProcIndex=%u (enter)\n", ProcIndex ));
  974. // Open/Close should never be called from a channel!
  975. ASSERT( ProcIndex != SD$OPEN && ProcIndex != SD$CLOSE );
  976. /*
  977. * Lock the connection object.
  978. * This will serialize all channel calls for this connection.
  979. */
  980. IcaLockConnection( pChannel->pConnect );
  981. /*
  982. * Send this call down to the stack(s).
  983. * If Passthru mode is enabled, then we bit bucket all channel I/O.
  984. * However if this channel is flagged as shadow persistent, let
  985. * the data go through.
  986. */
  987. if ( !pChannel->pConnect->fPassthruEnabled ||
  988. (pChannel->Flags & CHANNEL_SHADOW_PERSISTENT) ) {
  989. Head = &pChannel->pConnect->StackHead;
  990. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  991. pStack = CONTAINING_RECORD( Next, ICA_STACK, StackEntry );
  992. /*
  993. * If I/O is disabled for this stack, or if this is a
  994. * shadow stack and this call is from a channel that does
  995. * not process shadow I/O, or if it's a PassThru stack
  996. * and the channel is shadow persistent, then skip this stack.
  997. */
  998. if ( !(pStack->fIoDisabled ||
  999. pStack->StackClass == Stack_Shadow &&
  1000. !(pChannel->Flags & CHANNEL_SHADOW_IO) ||
  1001. (pChannel->pConnect->fPassthruEnabled &&
  1002. pStack->StackClass == Stack_Passthru)) ) {
  1003. Status = _IcaCallStack( pStack, ProcIndex, pParms );
  1004. }
  1005. }
  1006. }
  1007. /*
  1008. * Unlock the connection object now.
  1009. */
  1010. IcaUnlockConnection( pChannel->pConnect );
  1011. return( Status );
  1012. }
  1013. NTSTATUS
  1014. IcaCallNextDriver(
  1015. IN PSDCONTEXT pContext,
  1016. IN ULONG ProcIndex,
  1017. IN PVOID pParms
  1018. )
  1019. {
  1020. PSDLINK pSdLink;
  1021. PICA_STACK pStack;
  1022. NTSTATUS Status;
  1023. ASSERT( ProcIndex != SD$OPEN && ProcIndex != SD$CLOSE );
  1024. /*
  1025. * Use SD passed context to get the SDLINK object pointer.
  1026. */
  1027. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1028. pStack = pSdLink->pStack;
  1029. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1030. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1031. ASSERT( ExIsResourceAcquiredExclusiveLite( &pSdLink->pStack->Resource ) );
  1032. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API4, "TermDD: IcaCallNextDriver, ProcIndex=%u (enter)\n", ProcIndex ));
  1033. /*
  1034. * Call the next driver if there is one
  1035. */
  1036. if ( (pSdLink = IcaGetNextSdLink( pSdLink )) == NULL )
  1037. return( STATUS_INVALID_PARAMETER );
  1038. ASSERT( pSdLink->pStack == pStack );
  1039. Status = _IcaCallSd( pSdLink, ProcIndex, pParms );
  1040. return( Status );
  1041. }
  1042. NTSTATUS
  1043. IcaRawInput (
  1044. IN PSDCONTEXT pContext,
  1045. IN PINBUF pInBuf OPTIONAL,
  1046. IN PUCHAR pBuffer OPTIONAL,
  1047. IN ULONG ByteCount
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This is the input (stack callup) routine for ICA raw input.
  1052. Arguments:
  1053. pContext - Pointer to SDCONTEXT for this Stack Driver
  1054. pInBuf - Pointer to INBUF containing data
  1055. pBuffer - Pointer to input data
  1056. NOTE: Either pInBuf OR pBuffer must be specified, but not both.
  1057. ByteCount - length of data in pBuffer
  1058. Return Value:
  1059. NTSTATUS -- Indicates whether the request was handled successfully.
  1060. --*/
  1061. {
  1062. PSDLINK pSdLink;
  1063. PICA_STACK pStack;
  1064. PICA_CONNECTION pConnect;
  1065. NTSTATUS Status;
  1066. /*
  1067. * Use SD passed context to get the stack object pointer.
  1068. */
  1069. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1070. pStack = pSdLink->pStack; // save stack pointer for use below
  1071. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1072. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1073. TRACESTACK(( pStack, TC_ICADD, TT_API2, "TermDD: IcaRawInput, bc=%u (enter)\n", ByteCount ));
  1074. /*
  1075. * Only the stack object should be locked during input.
  1076. */
  1077. ASSERT( ExIsResourceAcquiredExclusiveLite( &pStack->Resource ) );
  1078. ASSERT( (pConnect = IcaGetConnectionForStack( pStack )) &&
  1079. !ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
  1080. /*
  1081. * Walk up the SDLINK list looking for a driver which has specified
  1082. * a RawInput callup routine. If we find one, then call the
  1083. * driver RawInput routine to let it handle the call.
  1084. */
  1085. while ( (pSdLink = IcaGetPreviousSdLink( pSdLink )) != NULL ) {
  1086. ASSERT( pSdLink->pStack == pStack );
  1087. if ( pSdLink->SdContext.pCallup->pSdRawInput ) {
  1088. IcaReferenceSdLink( pSdLink );
  1089. Status = (pSdLink->SdContext.pCallup->pSdRawInput)(
  1090. pSdLink->SdContext.pContext,
  1091. pInBuf,
  1092. pBuffer,
  1093. ByteCount );
  1094. IcaDereferenceSdLink( pSdLink );
  1095. return( Status );
  1096. }
  1097. }
  1098. return( IcaRawInputInternal( pStack, pInBuf, pBuffer, ByteCount ) );
  1099. }
  1100. NTSTATUS
  1101. IcaRawInputInternal(
  1102. IN PICA_STACK pStack,
  1103. IN PINBUF pInBuf OPTIONAL,
  1104. IN PCHAR pBuffer OPTIONAL,
  1105. IN ULONG ByteCount
  1106. )
  1107. {
  1108. SD_RAWWRITE SdRawWrite;
  1109. NTSTATUS Status;
  1110. /*
  1111. * See if passthru mode is enabled.
  1112. * If so, then we simply turn around and write the input data
  1113. * directly to the passthru stack.
  1114. */
  1115. if ( pStack->pPassthru ) {
  1116. PICA_STACK pPassthru;
  1117. if ( pInBuf ) {
  1118. SdRawWrite.pOutBuf = NULL;
  1119. SdRawWrite.pBuffer = pInBuf->pBuffer;
  1120. SdRawWrite.ByteCount = pInBuf->ByteCount;
  1121. } else {
  1122. SdRawWrite.pOutBuf = NULL;
  1123. SdRawWrite.pBuffer = pBuffer;
  1124. SdRawWrite.ByteCount = ByteCount;
  1125. }
  1126. // Grab a copy of pPassthru onto our local stack before we release
  1127. // the local stack lock. This has been a problem (NT bug #328433)
  1128. // where we release the local stack lock and pStack->pPassthru
  1129. // becomes NULL in _DisablePassthru() before we take out the
  1130. // passthrough stack lock inside of _IcaCallStack().
  1131. pPassthru = pStack->pPassthru;
  1132. // If data are being forwarded to the passthru, make
  1133. // sure it's fully initialized. If not, drop the data.
  1134. if((pPassthru->StackClass == Stack_Passthru) &&
  1135. pPassthru->fIoDisabled) {
  1136. return( STATUS_SUCCESS );
  1137. }
  1138. // Take a reference on the passthrough stack to make sure it does
  1139. // not go away before we get to it in the call below.
  1140. IcaReferenceStack(pPassthru);
  1141. // Unlock our current stack while in call to passthrough stack.
  1142. pStack->fDoingInput = TRUE;
  1143. IcaUnlockStack(pStack);
  1144. Status = _IcaCallStack(pPassthru, SD$RAWWRITE, &SdRawWrite);
  1145. IcaLockStack(pStack);
  1146. if ( pStack->fDisablingIo ) {
  1147. KeSetEvent( &pStack->IoEndEvent, 0, FALSE );
  1148. }
  1149. pStack->fDoingInput = FALSE;
  1150. // Mirror the refrence above.
  1151. IcaDereferenceStack(pPassthru);
  1152. /*
  1153. * Passthru is not enabled.
  1154. * We have no choice but to drop the input data.
  1155. */
  1156. } else {
  1157. Status = STATUS_SUCCESS;
  1158. }
  1159. return( Status );
  1160. }
  1161. NTSTATUS
  1162. IcaSleep(
  1163. IN PSDCONTEXT pContext,
  1164. IN ULONG Duration
  1165. )
  1166. {
  1167. PSDLINK pSdLink;
  1168. BOOLEAN LockStack = FALSE;
  1169. LARGE_INTEGER SleepTime;
  1170. NTSTATUS Status;
  1171. /*
  1172. * Use SD passed context to get the SDLINK object pointer.
  1173. */
  1174. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1175. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1176. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1177. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaSleep %d msec (enter)\n", Duration ));
  1178. /*
  1179. * Release stack lock if held
  1180. */
  1181. if ( ExIsResourceAcquiredExclusiveLite( &pSdLink->pStack->Resource ) ) {
  1182. LockStack = TRUE;
  1183. IcaUnlockStack( pSdLink->pStack );
  1184. }
  1185. /*
  1186. * Convert the sleep duration to a relative system time value and sleep.
  1187. */
  1188. SleepTime = RtlEnlargedIntegerMultiply( Duration, -10000 );
  1189. Status = KeDelayExecutionThread( KernelMode, TRUE, &SleepTime );
  1190. /*
  1191. * Reacquire stack lock if held on entry
  1192. */
  1193. if ( LockStack ) {
  1194. IcaLockStack( pSdLink->pStack );
  1195. }
  1196. /*
  1197. * If stack is being closed and we are returning success,
  1198. * then change return value to indicate stack is being closed.
  1199. */
  1200. if ( pSdLink->pStack->fClosing && Status == STATUS_SUCCESS )
  1201. Status = STATUS_CTX_CLOSE_PENDING;
  1202. #if DBG
  1203. if ( Status != STATUS_SUCCESS ) {
  1204. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: Sleep, ERROR 0x%x\n", Status ));
  1205. }
  1206. #endif
  1207. return( Status );
  1208. }
  1209. NTSTATUS
  1210. IcaWaitForSingleObject(
  1211. IN PSDCONTEXT pContext,
  1212. IN PVOID pObject,
  1213. IN LONG Timeout
  1214. )
  1215. {
  1216. PSDLINK pSdLink;
  1217. BOOLEAN LockStack = FALSE;
  1218. LARGE_INTEGER WaitTimeout;
  1219. PLARGE_INTEGER pWaitTimeout = NULL;
  1220. NTSTATUS Status;
  1221. /*
  1222. * Use SD passed context to get the SDLINK object pointer.
  1223. */
  1224. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1225. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1226. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1227. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API2, "TermDD: IcaWaitForSingleObject, %d (enter)\n", Timeout ));
  1228. /*
  1229. * Release stack lock if held
  1230. */
  1231. if ( ExIsResourceAcquiredExclusiveLite( &pSdLink->pStack->Resource ) ) {
  1232. LockStack = TRUE;
  1233. IcaUnlockStack( pSdLink->pStack );
  1234. }
  1235. /*
  1236. * Convert the timeout to a relative system time value and wait.
  1237. */
  1238. if ( Timeout != -1 ) {
  1239. ASSERT( Timeout >= 0 );
  1240. WaitTimeout = RtlEnlargedIntegerMultiply( Timeout, -10000 );
  1241. pWaitTimeout = &WaitTimeout;
  1242. }
  1243. Status = KeWaitForSingleObject( pObject, UserRequest, UserMode, FALSE,
  1244. pWaitTimeout );
  1245. /*
  1246. * Reacquire stack lock if held on entry
  1247. */
  1248. if ( LockStack ) {
  1249. IcaLockStack( pSdLink->pStack );
  1250. }
  1251. /*
  1252. * If stack is being closed and we are returning success,
  1253. * then change return value to indicate stack is being closed.
  1254. */
  1255. if ( pSdLink->pStack->fClosing && Status == STATUS_SUCCESS )
  1256. Status = STATUS_CTX_CLOSE_PENDING;
  1257. #if DBG
  1258. if ( Status != STATUS_SUCCESS ) {
  1259. if ( Status == STATUS_TIMEOUT ) {
  1260. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForSingleObject, TIMEOUT\n" ));
  1261. } else {
  1262. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForSingleObject, ERROR 0x%x\n", Status ));
  1263. }
  1264. }
  1265. #endif
  1266. return( Status );
  1267. }
  1268. /*
  1269. * Same as IcaSleep() except it is assumed that the connection lock is
  1270. * held. This is used by the VD flow control routines.
  1271. */
  1272. NTSTATUS
  1273. IcaFlowControlSleep(
  1274. IN PSDCONTEXT pContext,
  1275. IN ULONG Duration
  1276. )
  1277. {
  1278. PSDLINK pSdLink;
  1279. BOOLEAN LockStack = FALSE;
  1280. LARGE_INTEGER SleepTime;
  1281. NTSTATUS Status;
  1282. /*
  1283. * Use SD passed context to get the SDLINK object pointer.
  1284. */
  1285. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1286. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1287. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1288. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaSleep %d msec (enter)\n", Duration ));
  1289. /*
  1290. * Release stack lock if held
  1291. */
  1292. if ( ExIsResourceAcquiredExclusiveLite( &pSdLink->pStack->Resource ) ) {
  1293. LockStack = TRUE;
  1294. IcaUnlockStack( pSdLink->pStack );
  1295. }
  1296. /*
  1297. * Unlock the connection lock
  1298. */
  1299. IcaUnlockConnectionForStack( pSdLink->pStack );
  1300. /*
  1301. * Convert the sleep duration to a relative system time value and sleep.
  1302. */
  1303. SleepTime = RtlEnlargedIntegerMultiply( Duration, -10000 );
  1304. Status = KeDelayExecutionThread( KernelMode, TRUE, &SleepTime );
  1305. /*
  1306. * Relock the connection lock
  1307. */
  1308. IcaLockConnectionForStack( pSdLink->pStack );
  1309. /*
  1310. * Reacquire stack lock if held on entry
  1311. */
  1312. if ( LockStack ) {
  1313. IcaLockStack( pSdLink->pStack );
  1314. }
  1315. /*
  1316. * If stack is being closed and we are returning success,
  1317. * then change return value to indicate stack is being closed.
  1318. */
  1319. if ( pSdLink->pStack->fClosing && Status == STATUS_SUCCESS )
  1320. Status = STATUS_CTX_CLOSE_PENDING;
  1321. #if DBG
  1322. if ( Status != STATUS_SUCCESS ) {
  1323. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: Sleep, ERROR 0x%x\n", Status ));
  1324. }
  1325. #endif
  1326. return( Status );
  1327. }
  1328. /*
  1329. * Same as IcaWaitForSingleObject() except it is assumed that the connection lock is
  1330. * held. This is used by the VD flow control routines.
  1331. */
  1332. NTSTATUS
  1333. IcaFlowControlWait(
  1334. IN PSDCONTEXT pContext,
  1335. IN PVOID pObject,
  1336. IN LONG Timeout
  1337. )
  1338. {
  1339. PSDLINK pSdLink;
  1340. BOOLEAN LockStack = FALSE;
  1341. LARGE_INTEGER WaitTimeout;
  1342. PLARGE_INTEGER pWaitTimeout = NULL;
  1343. NTSTATUS Status;
  1344. /*
  1345. * Use SD passed context to get the SDLINK object pointer.
  1346. */
  1347. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1348. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1349. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1350. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API2, "TermDD: IcaWaitForSingleObject, %d (enter)\n", Timeout ));
  1351. /*
  1352. * Release stack lock if held
  1353. */
  1354. if ( ExIsResourceAcquiredExclusiveLite( &pSdLink->pStack->Resource ) ) {
  1355. LockStack = TRUE;
  1356. IcaUnlockStack( pSdLink->pStack );
  1357. }
  1358. /*
  1359. * Unlock the connection lock
  1360. */
  1361. IcaUnlockConnectionForStack( pSdLink->pStack );
  1362. /*
  1363. * Convert the timeout to a relative system time value and wait.
  1364. */
  1365. if ( Timeout != -1 ) {
  1366. ASSERT( Timeout >= 0 );
  1367. WaitTimeout = RtlEnlargedIntegerMultiply( Timeout, -10000 );
  1368. pWaitTimeout = &WaitTimeout;
  1369. }
  1370. Status = KeWaitForSingleObject( pObject, UserRequest, KernelMode, TRUE,
  1371. pWaitTimeout );
  1372. /*
  1373. * Relock the connection lock
  1374. */
  1375. IcaLockConnectionForStack( pSdLink->pStack );
  1376. /*
  1377. * Reacquire stack lock if held on entry
  1378. */
  1379. if ( LockStack ) {
  1380. IcaLockStack( pSdLink->pStack );
  1381. }
  1382. /*
  1383. * If stack is being closed and we are returning success,
  1384. * then change return value to indicate stack is being closed.
  1385. */
  1386. if ( pSdLink->pStack->fClosing && Status == STATUS_SUCCESS )
  1387. Status = STATUS_CTX_CLOSE_PENDING;
  1388. #if DBG
  1389. if ( Status != STATUS_SUCCESS ) {
  1390. if ( Status == STATUS_TIMEOUT ) {
  1391. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForSingleObject, TIMEOUT\n" ));
  1392. } else {
  1393. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForSingleObject, ERROR 0x%x\n", Status ));
  1394. }
  1395. }
  1396. #endif
  1397. return( Status );
  1398. }
  1399. NTSTATUS
  1400. IcaWaitForMultipleObjects(
  1401. IN PSDCONTEXT pContext,
  1402. IN ULONG Count,
  1403. IN PVOID Object[],
  1404. IN WAIT_TYPE WaitType,
  1405. IN LONG Timeout
  1406. )
  1407. {
  1408. PSDLINK pSdLink;
  1409. BOOLEAN LockStack = FALSE;
  1410. LARGE_INTEGER WaitTimeout;
  1411. PLARGE_INTEGER pWaitTimeout = NULL;
  1412. NTSTATUS Status;
  1413. /*
  1414. * Use SD passed context to get the SDLINK object pointer.
  1415. */
  1416. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1417. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1418. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1419. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForMultipleObjects, %d (enter)\n", Timeout ));
  1420. /*
  1421. * Release stack lock if held
  1422. */
  1423. if ( ExIsResourceAcquiredExclusiveLite( &pSdLink->pStack->Resource ) ) {
  1424. LockStack = TRUE;
  1425. IcaUnlockStack( pSdLink->pStack );
  1426. }
  1427. /*
  1428. * Convert the timeout to a relative system time value and wait.
  1429. */
  1430. if ( Timeout != -1 ) {
  1431. ASSERT( Timeout >= 0 );
  1432. WaitTimeout = RtlEnlargedIntegerMultiply( Timeout, -10000 );
  1433. pWaitTimeout = &WaitTimeout;
  1434. }
  1435. Status = KeWaitForMultipleObjects( Count, Object, WaitType, UserRequest,
  1436. KernelMode, TRUE, pWaitTimeout, NULL );
  1437. /*
  1438. * Reacquire stack lock if held on entry
  1439. */
  1440. if ( LockStack ) {
  1441. IcaLockStack( pSdLink->pStack );
  1442. }
  1443. /*
  1444. * If stack is being closed and we are returning success,
  1445. * then change return value to indicate stack is being closed.
  1446. */
  1447. if ( pSdLink->pStack->fClosing && Status == STATUS_SUCCESS )
  1448. Status = STATUS_CTX_CLOSE_PENDING;
  1449. #if DBG
  1450. if ( Status != STATUS_SUCCESS ) {
  1451. if ( Status == STATUS_TIMEOUT ) {
  1452. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForMultipleObjects, TIMEOUT\n" ));
  1453. } else {
  1454. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaWaitForMultipleObjects, ERROR 0x%x\n", Status ));
  1455. }
  1456. }
  1457. #endif
  1458. return( Status );
  1459. }
  1460. NTSTATUS
  1461. IcaLogError(
  1462. IN PSDCONTEXT pContext,
  1463. IN NTSTATUS Status,
  1464. IN LPWSTR * pArgStrings,
  1465. IN ULONG ArgStringCount,
  1466. IN PVOID pRawData,
  1467. IN ULONG RawDataLength
  1468. )
  1469. {
  1470. return( _LogError( IcaDeviceObject, Status, pArgStrings, ArgStringCount, pRawData, RawDataLength ) );
  1471. }
  1472. NTSTATUS
  1473. _LogError(
  1474. IN PDEVICE_OBJECT pDeviceObject,
  1475. IN NTSTATUS Status,
  1476. IN LPWSTR * pArgStrings,
  1477. IN ULONG ArgStringCount,
  1478. IN PVOID pRawData,
  1479. IN ULONG RawDataLength
  1480. )
  1481. {
  1482. LPWSTR *TmpPtr;
  1483. PUCHAR ptrToString;
  1484. ULONG Tmp, StringSize, TotalStringSize;
  1485. PIO_ERROR_LOG_PACKET errorLogEntry;
  1486. // Get the bytes needed for strings storage
  1487. Tmp = ArgStringCount;
  1488. TmpPtr = pArgStrings;
  1489. TotalStringSize = 0;
  1490. while( Tmp ) {
  1491. TotalStringSize += ((wcslen(*TmpPtr)+1)*sizeof(WCHAR));
  1492. Tmp--;
  1493. TmpPtr++;
  1494. }
  1495. errorLogEntry = IoAllocateErrorLogEntry(
  1496. pDeviceObject,
  1497. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
  1498. RawDataLength +
  1499. TotalStringSize)
  1500. );
  1501. if ( errorLogEntry != NULL ) {
  1502. errorLogEntry->ErrorCode = Status;
  1503. errorLogEntry->SequenceNumber = 0;
  1504. errorLogEntry->MajorFunctionCode = 0;
  1505. errorLogEntry->RetryCount = 0;
  1506. errorLogEntry->UniqueErrorValue = 0;
  1507. errorLogEntry->FinalStatus = Status;
  1508. errorLogEntry->DumpDataSize = (USHORT)RawDataLength;
  1509. // Copy raw data
  1510. if (RawDataLength) {
  1511. RtlCopyMemory(
  1512. &errorLogEntry->DumpData[0],
  1513. pRawData,
  1514. RawDataLength
  1515. );
  1516. ptrToString =
  1517. ((PUCHAR)&errorLogEntry->DumpData[0])+RawDataLength;
  1518. } else {
  1519. ptrToString = (PUCHAR)&errorLogEntry->DumpData[0];
  1520. }
  1521. // round up to next word boundary
  1522. // it's ok to add 1 byte because we allocated more bytes than we needed:
  1523. // the number of extra bytes is the size of DumpData which is ULONG.
  1524. ptrToString = (PUCHAR)((ULONG_PTR)(ptrToString + sizeof(WCHAR) - 1) & ~(ULONG_PTR)(sizeof(WCHAR) - 1));
  1525. // Copy strings following raw data
  1526. errorLogEntry->NumberOfStrings = (USHORT)ArgStringCount;
  1527. if( ArgStringCount ) {
  1528. errorLogEntry->StringOffset = (USHORT)(ptrToString -
  1529. (PUCHAR)errorLogEntry);
  1530. }
  1531. else {
  1532. errorLogEntry->StringOffset = 0;
  1533. }
  1534. while( ArgStringCount ) {
  1535. StringSize = (wcslen(*pArgStrings)+1)*sizeof(WCHAR);
  1536. RtlCopyMemory(
  1537. ptrToString,
  1538. *pArgStrings,
  1539. StringSize
  1540. );
  1541. ptrToString += StringSize;
  1542. ArgStringCount--;
  1543. pArgStrings++;
  1544. }
  1545. IoWriteErrorLogEntry(errorLogEntry);
  1546. return STATUS_SUCCESS;
  1547. }
  1548. else {
  1549. return STATUS_NO_MEMORY;
  1550. }
  1551. }
  1552. #define KEEP_ALIVE_MIN_INTERVAL 50000000 // 5 sec in terms of 100 nanosecs
  1553. VOID
  1554. IcaCheckStackAlive( )
  1555. {
  1556. NTSTATUS status;
  1557. KIRQL OldIrql;
  1558. PICA_STACK pStack;
  1559. SD_IOCTL SdIoctl;
  1560. LARGE_INTEGER SleepTime;
  1561. LARGE_INTEGER CurrentTime;
  1562. LONGLONG KeepAliveInterval;
  1563. while (TRUE) {
  1564. KeepAliveInterval = g_KeepAliveInterval * 600000000 ; // in 100 nanosecs
  1565. pStack = NULL;
  1566. // Lock the stack list for reading
  1567. IcaAcquireSpinLock(&IcaStackListSpinLock, &OldIrql);
  1568. //KdPrint(("Total number of stacks: %d\n", IcaTotalNumOfStacks));
  1569. // determine new sleep time for the keepalive thread
  1570. // it is the keepalive interval for a stack divided by total
  1571. // number of stacks
  1572. // the low threshold for sleep time is 5 sec. Since relative
  1573. // sleeptime is a negative value, we use min instead of max
  1574. if (IcaTotalNumOfStacks > 1) {
  1575. SleepTime.QuadPart = min(0 - KEEP_ALIVE_MIN_INTERVAL,
  1576. 0 - (KeepAliveInterval / IcaTotalNumOfStacks));
  1577. }
  1578. else {
  1579. SleepTime.QuadPart = min(0 - KEEP_ALIVE_MIN_INTERVAL,
  1580. 0 - KeepAliveInterval);
  1581. }
  1582. // If the stack list is not empty, get the stack for keepalive
  1583. // checking and move the IcaNextStack pointer to the next stack
  1584. if (IcaNextStack != &IcaStackListHead) {
  1585. pStack = CONTAINING_RECORD(IcaNextStack, ICA_STACK, StackNode);
  1586. // Reference the stack so that the stack won't be deleted while we
  1587. // are accessing it
  1588. IcaReferenceStack(pStack);
  1589. IcaNextStack = IcaNextStack->Flink;
  1590. }
  1591. else {
  1592. if (IcaNextStack->Flink != &IcaStackListHead) {
  1593. pStack = CONTAINING_RECORD(IcaNextStack->Flink, ICA_STACK, StackNode);
  1594. // Reference the stack so that the stack won't be deleted while we
  1595. // are accessing it
  1596. IcaReferenceStack(pStack);
  1597. IcaNextStack = IcaNextStack->Flink->Flink;
  1598. }
  1599. }
  1600. // Unlock the stack list now
  1601. IcaReleaseSpinLock(&IcaStackListSpinLock, OldIrql);
  1602. // If the stack pointer is invalid or LastInputTime on the stack is 0,
  1603. // the stack is not in the active state, so we don't need to send
  1604. // keepalive pkt on that stack.
  1605. if (pStack != NULL && pStack->LastInputTime.QuadPart != 0) {
  1606. // Get the current system time
  1607. KeQuerySystemTime(&CurrentTime);
  1608. // Check if it is time to send a keepalive packet depends on
  1609. // the keepalive timestamp and lastinput timestamp
  1610. if (CurrentTime.QuadPart - pStack->LastKeepAliveTime.QuadPart >= KeepAliveInterval &&
  1611. CurrentTime.QuadPart - pStack->LastInputTime.QuadPart >= KeepAliveInterval) {
  1612. // Initialize the IOCTL struct
  1613. SdIoctl.IoControlCode = IOCTL_ICA_STACK_SEND_KEEPALIVE_PDU;
  1614. SdIoctl.InputBuffer = NULL;
  1615. SdIoctl.InputBufferLength = 0;
  1616. SdIoctl.OutputBuffer = NULL;
  1617. SdIoctl.OutputBufferLength = 0;
  1618. //KdPrint(("In IcaCheckStackAlive: To call WD, pStack=%p\n", pStack));
  1619. // Send an IOCTL to the stack requesting to send a keepalive packet
  1620. _IcaCallStack(pStack, SD$IOCTL, &SdIoctl);
  1621. // Update the LastKeepAlive timestamp for the stack
  1622. KeQuerySystemTime(&pStack->LastKeepAliveTime);
  1623. }
  1624. #if DBG
  1625. else {
  1626. if (CurrentTime.QuadPart - pStack->LastKeepAliveTime.QuadPart < KeepAliveInterval) {
  1627. //KdPrint(("Not time to do keep alive yet, pstack=%p\n", pStack));
  1628. }
  1629. if (CurrentTime.QuadPart - pStack->LastInputTime.QuadPart < KeepAliveInterval) {
  1630. //KdPrint(("- Last Input Time is less than KeepAliveInterval, pstack=%p\n", pStack));
  1631. }
  1632. }
  1633. #endif
  1634. }
  1635. #if DBG
  1636. else{
  1637. if (pStack != NULL) {
  1638. //KdPrint(("No need to send KeepAlive PDU on pstack=%p\n", pStack));
  1639. }
  1640. }
  1641. #endif
  1642. // Decrement the reference to the stack so that it can be deleted
  1643. if (pStack != NULL) {
  1644. IcaDereferenceStack(pStack);
  1645. }
  1646. // Start sleep timer again
  1647. // We would return if the unload module signal the IcaKeepAliveEvent
  1648. // to stop this keepalive thread
  1649. status = KeWaitForSingleObject(pIcaKeepAliveEvent, Executive, KernelMode, TRUE, &SleepTime);
  1650. if (status == STATUS_SUCCESS) {
  1651. return;
  1652. }
  1653. }
  1654. }
  1655. VOID
  1656. IcaKeepAliveThread(
  1657. IN PVOID pData)
  1658. {
  1659. IcaCheckStackAlive();
  1660. }
  1661. #ifdef notdef
  1662. VOID
  1663. IcaAcquireIoLock(
  1664. IN PSDCONTEXT pContext
  1665. )
  1666. {
  1667. PSDLINK pSdLink;
  1668. /*
  1669. * Use SD passed context to get the SDLINK object pointer.
  1670. */
  1671. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1672. IcaLockConnectionForStack( pSdLink->pStack );
  1673. }
  1674. VOID
  1675. IcaReleaseIoLock(
  1676. IN PSDCONTEXT pContext
  1677. )
  1678. {
  1679. PSDLINK pSdLink;
  1680. /*
  1681. * Use SD passed context to get the SDLINK object pointer.
  1682. */
  1683. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1684. IcaUnlockConnectionForStack( pSdLink->pStack );
  1685. }
  1686. VOID
  1687. IcaAcquireDriverLock(
  1688. IN PSDCONTEXT pContext
  1689. )
  1690. {
  1691. PSDLINK pSdLink;
  1692. /*
  1693. * Use SD passed context to get the SDLINK object pointer.
  1694. */
  1695. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1696. IcaLockStack( pSdLink->pStack );
  1697. }
  1698. VOID
  1699. IcaReleaseDriverLock(
  1700. IN PSDCONTEXT pContext
  1701. )
  1702. {
  1703. PSDLINK pSdLink;
  1704. /*
  1705. * Use SD passed context to get the SDLINK object pointer.
  1706. */
  1707. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1708. IcaUnlockStack( pSdLink->pStack );
  1709. }
  1710. VOID
  1711. IcaIncrementDriverReference(
  1712. IN PSDCONTEXT pContext
  1713. )
  1714. {
  1715. PSDLINK pSdLink;
  1716. /*
  1717. * Use SD passed context to get the SDLINK object pointer.
  1718. */
  1719. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1720. IcaReferenceSdLink( pSdLink );
  1721. }
  1722. VOID
  1723. IcaDecrementDriverReference(
  1724. IN PSDCONTEXT pContext
  1725. )
  1726. {
  1727. PSDLINK pSdLink;
  1728. /*
  1729. * Use SD passed context to get the SDLINK object pointer.
  1730. */
  1731. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1732. IcaDereferenceSdLink( pSdLink );
  1733. }
  1734. #endif
  1735. typedef NTSTATUS (*PTHREAD_ROUTINE) ( PVOID );
  1736. typedef struct _ICACREATETHREADINFO {
  1737. PTHREAD_ROUTINE pProc;
  1738. PVOID pParm;
  1739. PSDLINK pSdLink;
  1740. ULONG LockFlags;
  1741. } ICACREATETHREADINFO, *PICACREATETHREADINFO;
  1742. NTSTATUS
  1743. IcaCreateThread(
  1744. IN PSDCONTEXT pContext,
  1745. IN PVOID pProc,
  1746. IN PVOID pParm,
  1747. IN ULONG LockFlags,
  1748. OUT PHANDLE pThreadHandle
  1749. )
  1750. {
  1751. PSDLINK pSdLink;
  1752. PICACREATETHREADINFO pThreadInfo;
  1753. NTSTATUS Status;
  1754. /*
  1755. * Use SD passed context to get the SDLINK object pointer.
  1756. */
  1757. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1758. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1759. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1760. TRACESTACK(( pSdLink->pStack, TC_ICADD, TT_API1, "TermDD: IcaCreateThread (enter)\n" ));
  1761. pThreadInfo = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pThreadInfo) );
  1762. if ( pThreadInfo == NULL )
  1763. return( STATUS_NO_MEMORY );
  1764. pThreadInfo->pProc = pProc;
  1765. pThreadInfo->pParm = pParm;
  1766. pThreadInfo->pSdLink = pSdLink;
  1767. pThreadInfo->LockFlags = LockFlags;
  1768. /*
  1769. * Reference the SDLINK object on behalf of the new thread.
  1770. */
  1771. IcaReferenceSdLink( pSdLink );
  1772. Status = PsCreateSystemThread( pThreadHandle,
  1773. THREAD_ALL_ACCESS,
  1774. NULL,
  1775. NtCurrentProcess(),
  1776. NULL,
  1777. _IcaDriverThread,
  1778. (PVOID) pThreadInfo );
  1779. if ( !NT_SUCCESS( Status ) ) {
  1780. IcaDereferenceSdLink( pSdLink );
  1781. ICA_FREE_POOL( pThreadInfo );
  1782. return( Status );
  1783. }
  1784. return( STATUS_SUCCESS );
  1785. }
  1786. NTSTATUS
  1787. _IcaDriverThread(
  1788. IN PVOID pData
  1789. )
  1790. {
  1791. PICACREATETHREADINFO pThreadInfo = (PICACREATETHREADINFO)pData;
  1792. PTHREAD_ROUTINE pProc;
  1793. PVOID pParm;
  1794. PSDLINK pSdLink;
  1795. PICA_STACK pStack;
  1796. ULONG LockFlags;
  1797. NTSTATUS Status;
  1798. pProc = pThreadInfo->pProc;
  1799. pParm = pThreadInfo->pParm;
  1800. pSdLink = pThreadInfo->pSdLink;
  1801. LockFlags = pThreadInfo->LockFlags;
  1802. ICA_FREE_POOL( pThreadInfo );
  1803. pStack = pSdLink->pStack;
  1804. /*
  1805. * Obtain any required locks before calling the worker routine.
  1806. */
  1807. ASSERT( !(LockFlags & ICALOCK_IO) );
  1808. if ( LockFlags & ICALOCK_DRIVER )
  1809. IcaLockStack( pStack );
  1810. /*
  1811. * Call the thread routine
  1812. */
  1813. #if DBG
  1814. try {
  1815. #endif
  1816. /*
  1817. * If stack is being closed, then indicate this to caller.
  1818. */
  1819. if ( !pStack->fClosing )
  1820. Status = (pProc)( pParm );
  1821. else
  1822. Status = STATUS_CTX_CLOSE_PENDING;
  1823. #if DBG
  1824. } except( IcaExceptionFilter( L"_IcaDriverThread TRAPPED!!",
  1825. GetExceptionInformation() ) ) {
  1826. Status = GetExceptionCode();
  1827. }
  1828. #endif
  1829. /*
  1830. * Release any locks acquired above.
  1831. */
  1832. if ( LockFlags & ICALOCK_DRIVER )
  1833. IcaUnlockStack( pStack );
  1834. /*
  1835. * Dereference the SDLINK object now.
  1836. * This undoes the reference that was made on our behalf in
  1837. * the IcaCreateThread routine when this thread was created.
  1838. */
  1839. IcaDereferenceSdLink( pSdLink );
  1840. return( Status );
  1841. }
  1842. PICA_STACK
  1843. _IcaAllocateStack( VOID )
  1844. {
  1845. PICA_STACK pStack;
  1846. NTSTATUS Status;
  1847. /*
  1848. * Allocate and initialize stack structure
  1849. */
  1850. pStack = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pStack) );
  1851. if ( pStack == NULL )
  1852. return NULL;
  1853. RtlZeroMemory( pStack, sizeof(*pStack) );
  1854. /*
  1855. * Initialize the reference count to 2,
  1856. * one for the caller's reference, one for the file object reference.
  1857. */
  1858. pStack->RefCount = 2;
  1859. /*
  1860. * Initialize the rest of the stack object
  1861. */
  1862. pStack->Header.Type = IcaType_Stack;
  1863. pStack->Header.pDispatchTable = IcaStackDispatchTable;
  1864. ExInitializeResourceLite( &pStack->Resource );
  1865. InitializeListHead( &pStack->SdLinkHead );
  1866. KeInitializeEvent( &pStack->OutBufEvent, NotificationEvent, FALSE );
  1867. KeInitializeEvent( &pStack->IoEndEvent, NotificationEvent, FALSE );
  1868. return( pStack );
  1869. }
  1870. VOID
  1871. _IcaFreeStack( PICA_STACK pStack )
  1872. {
  1873. PICA_CONNECTION pConnect;
  1874. ASSERT( pStack->RefCount == 0 );
  1875. ASSERT( IsListEmpty( &pStack->SdLinkHead ) );
  1876. ASSERT( !ExIsResourceAcquiredExclusiveLite( &pStack->Resource ) );
  1877. /*
  1878. * Remove the reference to the Connection object for this stack.
  1879. */
  1880. pConnect = (PICA_CONNECTION)pStack->pConnect;
  1881. IcaDereferenceConnection( pConnect );
  1882. ExDeleteResourceLite( &pStack->Resource );
  1883. ICA_FREE_POOL( pStack );
  1884. }
  1885. NTSTATUS
  1886. _IcaPushStack(
  1887. IN PICA_STACK pStack,
  1888. IN PICA_STACK_PUSH pStackPush
  1889. )
  1890. {
  1891. PSD_OPEN pSdOpen = NULL;
  1892. PSDLINK pSdLink;
  1893. NTSTATUS Status;
  1894. if ( g_TermServProcessID == NULL)
  1895. {
  1896. g_TermServProcessID = IoGetCurrentProcess();
  1897. }
  1898. /*
  1899. * Serialize all stack push/pop/call operations
  1900. */
  1901. IcaLockStack( pStack );
  1902. TRACESTACK(( pStack, TC_ICADD, TT_API1, "TermDD: _IcaPushStack, type %u, name %S (enter)\n",
  1903. pStackPush->StackModuleType, pStackPush->StackModuleName ));
  1904. /*
  1905. * If stack is being closed, then indicate this to caller
  1906. */
  1907. if ( pStack->fClosing ) {
  1908. Status = STATUS_CTX_CLOSE_PENDING;
  1909. goto done;
  1910. }
  1911. pSdOpen = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(SD_OPEN) );
  1912. if ( pSdOpen == NULL ) {
  1913. Status = STATUS_NO_MEMORY;
  1914. goto done;
  1915. }
  1916. /*
  1917. * Load an instance of the requested stack driver
  1918. */
  1919. Status = _IcaLoadSd( pStackPush->StackModuleName, &pSdLink );
  1920. if ( !NT_SUCCESS( Status ) )
  1921. goto done;
  1922. /*
  1923. * If this is the first stack driver loaded, then initialize
  1924. * some of the stack data from the ICA_STACK_PUSH parameters.
  1925. * NOTE: Since we're testing for an empty list we must make
  1926. * this check before the InsertHeadList below.
  1927. */
  1928. if ( IsListEmpty( &pStack->SdLinkHead ) ) {
  1929. pStack->OutBufLength = pStackPush->PdConfig.Create.OutBufLength;
  1930. pStack->OutBufCount = pStackPush->PdConfig.Create.OutBufCount;
  1931. //
  1932. //Set the low water mark using the PD config
  1933. //
  1934. if ( !(pStackPush->PdConfig.Create.PdFlag & PD_NOLOW_WATERMARK) ) {
  1935. //
  1936. //set to default
  1937. //
  1938. pStack->OutBufLowWaterMark = (pStackPush->PdConfig.Create.OutBufCount/ 3) + 1;
  1939. }
  1940. else {
  1941. pStack->OutBufLowWaterMark = MAX_LOW_WATERMARK;
  1942. }
  1943. }
  1944. /*
  1945. * Increment the stack ref count for this SD,
  1946. * and push the new SD on the stack.
  1947. */
  1948. IcaReferenceStack( pStack );
  1949. InsertHeadList( &pStack->SdLinkHead, &pSdLink->Links );
  1950. pSdLink->pStack = pStack;
  1951. /*
  1952. * Initialize the SD open parameters
  1953. */
  1954. pSdOpen->StackClass = pStack->StackClass;
  1955. pSdOpen->pStatus = &pStack->ProtocolStatus;
  1956. pSdOpen->pClient = &pStack->ClientModules;
  1957. pSdOpen->WdConfig = pStackPush->WdConfig;
  1958. pSdOpen->PdConfig = pStackPush->PdConfig;
  1959. pSdOpen->OutBufHeader = pStack->SdOutBufHeader;
  1960. pSdOpen->OutBufTrailer = pStack->SdOutBufTrailer;
  1961. pSdOpen->DeviceObject = pSdLink->pSdLoad->DeviceObject;
  1962. RtlCopyMemory( pSdOpen->OEMId, pStackPush->OEMId, sizeof(pSdOpen->OEMId) );
  1963. RtlCopyMemory( pSdOpen->WinStationRegName, pStackPush->WinStationRegName,
  1964. sizeof(pSdOpen->WinStationRegName) );
  1965. /*
  1966. * Call the SD open procedure
  1967. */
  1968. Status = _IcaCallSd( pSdLink, SD$OPEN, pSdOpen );
  1969. if ( !NT_SUCCESS( Status ) ) {
  1970. RemoveEntryList( &pSdLink->Links );
  1971. pSdLink->Links.Flink = pSdLink->Links.Blink = NULL;
  1972. IcaDereferenceSdLink( pSdLink );
  1973. goto done;
  1974. }
  1975. /*
  1976. * Increment number of reserved output buffer bytes
  1977. */
  1978. pStack->SdOutBufHeader += pSdOpen->SdOutBufHeader;
  1979. pStack->SdOutBufTrailer += pSdOpen->SdOutBufTrailer;
  1980. done:
  1981. if ( pSdOpen ) {
  1982. ICA_FREE_POOL( pSdOpen );
  1983. }
  1984. IcaUnlockStack( pStack );
  1985. return( Status );
  1986. }
  1987. NTSTATUS
  1988. _IcaPopStack(
  1989. IN PICA_STACK pStack
  1990. )
  1991. {
  1992. PICA_CONNECTION pConnect;
  1993. SD_CLOSE SdClose;
  1994. PSDLINK pSdLink;
  1995. NTSTATUS Status;
  1996. /*
  1997. * Serialize all stack push/pop/call operations
  1998. */
  1999. IcaLockStack( pStack );
  2000. ASSERT( (pConnect = IcaGetConnectionForStack( pStack )) &&
  2001. ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
  2002. /*
  2003. * If no SDs remain, then return error
  2004. */
  2005. if ( IsListEmpty( &pStack->SdLinkHead ) ) {
  2006. Status = STATUS_NO_MORE_ENTRIES;
  2007. goto done;
  2008. }
  2009. /*
  2010. * Call the SD close procedure for the topmost SD
  2011. */
  2012. pSdLink = CONTAINING_RECORD( pStack->SdLinkHead.Flink, SDLINK, Links );
  2013. ASSERT( pSdLink->pStack == pStack );
  2014. Status = _IcaCallSd( pSdLink, SD$CLOSE, &SdClose );
  2015. /*
  2016. * Decrement number of reserved output buffer bytes
  2017. */
  2018. pStack->SdOutBufHeader -= SdClose.SdOutBufHeader;
  2019. pStack->SdOutBufTrailer -= SdClose.SdOutBufTrailer;
  2020. /*
  2021. * Remove the SdLink from the top of the list,
  2022. * and dereference the SDLINK object.
  2023. */
  2024. RemoveEntryList( &pSdLink->Links );
  2025. pSdLink->Links.Flink = pSdLink->Links.Blink = NULL;
  2026. IcaDereferenceSdLink( pSdLink );
  2027. done:
  2028. IcaUnlockStack( pStack );
  2029. return( Status );
  2030. }
  2031. NTSTATUS
  2032. _IcaCallStack(
  2033. IN PICA_STACK pStack,
  2034. IN ULONG ProcIndex,
  2035. IN OUT PVOID pParms
  2036. )
  2037. {
  2038. PLIST_ENTRY Head;
  2039. PSDLINK pSdLink;
  2040. NTSTATUS Status;
  2041. /*
  2042. * Serialize all stack push/pop/call operations
  2043. */
  2044. IcaLockStack( pStack );
  2045. /*
  2046. * Call the topmost Stack Driver, if there is one
  2047. */
  2048. if ( IsListEmpty( &pStack->SdLinkHead ) ) {
  2049. IcaUnlockStack( pStack );
  2050. return( STATUS_INVALID_PARAMETER );
  2051. }
  2052. Head = pStack->SdLinkHead.Flink;
  2053. pSdLink = CONTAINING_RECORD( Head, SDLINK, Links );
  2054. ASSERT( pSdLink->pStack == pStack );
  2055. Status = _IcaCallSd( pSdLink, ProcIndex, pParms );
  2056. IcaUnlockStack( pStack );
  2057. return( Status );
  2058. }
  2059. NTSTATUS
  2060. _IcaCallStackNoLock(
  2061. IN PICA_STACK pStack,
  2062. IN ULONG ProcIndex,
  2063. IN OUT PVOID pParms
  2064. )
  2065. {
  2066. PLIST_ENTRY Head;
  2067. PSDLINK pSdLink;
  2068. NTSTATUS Status;
  2069. /*
  2070. * Call the topmost Stack Driver, if there is one
  2071. */
  2072. if ( IsListEmpty( &pStack->SdLinkHead ) ) {
  2073. return( STATUS_INVALID_PARAMETER );
  2074. }
  2075. Head = pStack->SdLinkHead.Flink;
  2076. pSdLink = CONTAINING_RECORD( Head, SDLINK, Links );
  2077. ASSERT( pSdLink->pStack == pStack );
  2078. Status = _IcaCallSd( pSdLink, ProcIndex, pParms );
  2079. return( Status );
  2080. }
  2081. NTSTATUS
  2082. _IcaLoadSd(
  2083. IN PDLLNAME SdName,
  2084. OUT PSDLINK *ppSdLink
  2085. )
  2086. {
  2087. PSDLINK pSdLink;
  2088. PSDLOAD pSdLoad;
  2089. PLIST_ENTRY Head, Next;
  2090. NTSTATUS Status;
  2091. /*
  2092. * Allocate a SDLINK struct
  2093. */
  2094. pSdLink = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pSdLink) );
  2095. if ( pSdLink == NULL )
  2096. return( STATUS_INSUFFICIENT_RESOURCES );
  2097. RtlZeroMemory( pSdLink, sizeof(*pSdLink) );
  2098. /*
  2099. * Initialize reference count
  2100. */
  2101. pSdLink->RefCount = 1;
  2102. #if DBG
  2103. ExInitializeResourceLite( &pSdLink->Resource );
  2104. #endif
  2105. /*
  2106. * Lock the ICA Resource exclusively to search the SdLoad list.
  2107. * Note when holding a resource we need to prevent APC calls, so
  2108. * use KeEnterCriticalRegion().
  2109. */
  2110. KeEnterCriticalRegion();
  2111. ExAcquireResourceExclusiveLite( IcaSdLoadResource, TRUE );
  2112. /*
  2113. * Look for the requested SD. If found, increment the ref count for it.
  2114. */
  2115. Head = &IcaSdLoadListHead;
  2116. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  2117. pSdLoad = CONTAINING_RECORD( Next, SDLOAD, Links );
  2118. if ( !wcscmp( pSdLoad->SdName, SdName ) ) {
  2119. _IcaReferenceSdLoad( pSdLoad );
  2120. break;
  2121. }
  2122. }
  2123. /*
  2124. * If the requested SD was not found, then load it now.
  2125. */
  2126. if ( Next == Head ) {
  2127. Status = _IcaLoadSdWorker( SdName, &pSdLoad );
  2128. if ( !NT_SUCCESS( Status ) ) {
  2129. ExReleaseResourceLite( IcaSdLoadResource );
  2130. KeLeaveCriticalRegion();
  2131. #if DBG
  2132. ExDeleteResourceLite( &pSdLink->Resource);
  2133. #endif
  2134. ICA_FREE_POOL( pSdLink );
  2135. return( Status );
  2136. }
  2137. }
  2138. ExReleaseResourceLite( IcaSdLoadResource );
  2139. KeLeaveCriticalRegion();
  2140. pSdLink->pSdLoad = pSdLoad;
  2141. /*
  2142. * Call the driver load procedure.
  2143. * The driver will fill in the fields in the SDCONTEXT structure.
  2144. */
  2145. Status = (pSdLoad->DriverLoad)( &pSdLink->SdContext, TRUE );
  2146. if ( !NT_SUCCESS( Status ) ) {
  2147. KeEnterCriticalRegion();
  2148. ExAcquireResourceExclusiveLite( IcaSdLoadResource, TRUE );
  2149. _IcaDereferenceSdLoad( pSdLink->pSdLoad );
  2150. ExReleaseResourceLite( IcaSdLoadResource );
  2151. KeLeaveCriticalRegion();
  2152. #if DBG
  2153. ExDeleteResourceLite( &pSdLink->Resource );
  2154. #endif
  2155. ICA_FREE_POOL( pSdLink );
  2156. return( Status );
  2157. }
  2158. *ppSdLink = pSdLink;
  2159. return( Status );
  2160. }
  2161. NTSTATUS
  2162. _IcaUnloadSd(
  2163. IN PSDLINK pSdLink
  2164. )
  2165. {
  2166. KIRQL oldIrql;
  2167. NTSTATUS Status;
  2168. ASSERT( pSdLink->RefCount == 0 );
  2169. ASSERT( pSdLink->Links.Flink == NULL );
  2170. /*
  2171. * Inform driver of unload
  2172. */
  2173. Status = (pSdLink->pSdLoad->DriverLoad)( &pSdLink->SdContext, FALSE );
  2174. /*
  2175. * Decrement ref count on SdLoad object.
  2176. * This will cause it to be unloaded if the ref count goes to 0.
  2177. * Note that while holding a resource we need to disable APC calls,
  2178. * hence the CriticalRegion calls.
  2179. */
  2180. KeEnterCriticalRegion();
  2181. ExAcquireResourceExclusiveLite( IcaSdLoadResource, TRUE );
  2182. _IcaDereferenceSdLoad( pSdLink->pSdLoad );
  2183. ExReleaseResourceLite( IcaSdLoadResource );
  2184. KeLeaveCriticalRegion();
  2185. /*
  2186. * Remove reference this SDLINK object had on the stack.
  2187. */
  2188. IcaDereferenceStack( pSdLink->pStack );
  2189. #if DBG
  2190. ExDeleteResourceLite( &pSdLink->Resource );
  2191. #endif
  2192. ICA_FREE_POOL( pSdLink );
  2193. return( Status );
  2194. }
  2195. NTSTATUS
  2196. _IcaCallSd(
  2197. IN PSDLINK pSdLink,
  2198. IN ULONG ProcIndex,
  2199. IN PVOID pParms
  2200. )
  2201. {
  2202. PSDPROCEDURE pSdProcedure;
  2203. NTSTATUS Status;
  2204. /*
  2205. * If there is no procedure call table, return success.
  2206. * This should only happen during load/unload and should not be a problem.
  2207. */
  2208. if ( pSdLink->SdContext.pProcedures == NULL )
  2209. return( STATUS_SUCCESS );
  2210. /*
  2211. * Get a pointer to the SD proc based on specified ProcIndex.
  2212. * If NULL, then this ProcIndex is not supported by this driver.
  2213. */
  2214. pSdProcedure = ((PSDPROCEDURE *)pSdLink->SdContext.pProcedures)[ ProcIndex ];
  2215. if ( pSdProcedure == NULL )
  2216. return( STATUS_NOT_SUPPORTED );
  2217. IcaReferenceSdLink( pSdLink );
  2218. Status = (pSdProcedure)( pSdLink->SdContext.pContext, pParms );
  2219. IcaDereferenceSdLink( pSdLink );
  2220. return( Status );
  2221. }
  2222. VOID
  2223. IcaReferenceSdLink(
  2224. IN PSDLINK pSdLink
  2225. )
  2226. {
  2227. ASSERT( pSdLink->RefCount >= 0 );
  2228. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  2229. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  2230. /*
  2231. * Increment the reference count
  2232. */
  2233. if ( InterlockedIncrement( &pSdLink->RefCount) <= 0 ) {
  2234. ASSERT( FALSE );
  2235. }
  2236. }
  2237. VOID
  2238. IcaDereferenceSdLink(
  2239. IN PSDLINK pSdLink
  2240. )
  2241. {
  2242. ASSERT( pSdLink->RefCount > 0 );
  2243. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  2244. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  2245. /*
  2246. * Decrement the reference count; if it is 0, unload the SD.
  2247. */
  2248. if ( InterlockedDecrement( &pSdLink->RefCount) == 0 ) {
  2249. _IcaUnloadSd( pSdLink );
  2250. }
  2251. }
  2252. PSDLINK
  2253. IcaGetNextSdLink(
  2254. IN PSDLINK pSdLink
  2255. )
  2256. {
  2257. PLIST_ENTRY Next;
  2258. PSDLINK pNextSdLink;
  2259. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  2260. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  2261. ASSERT( pSdLink->RefCount > 0 || pSdLink->Links.Flink == NULL );
  2262. ASSERT( pSdLink->SdContext.pProcedures );
  2263. ASSERT( pSdLink->SdContext.pContext );
  2264. if ( pSdLink->Links.Flink == NULL )
  2265. return( NULL );
  2266. Next = pSdLink->Links.Flink;
  2267. if ( Next == &pSdLink->pStack->SdLinkHead )
  2268. return( NULL );
  2269. pNextSdLink = CONTAINING_RECORD( Next, SDLINK, Links );
  2270. ASSERT( pNextSdLink->pStack == pSdLink->pStack );
  2271. ASSERT( pNextSdLink->RefCount > 0 );
  2272. ASSERT( pNextSdLink->SdContext.pProcedures );
  2273. ASSERT( pNextSdLink->SdContext.pContext );
  2274. return( pNextSdLink );
  2275. }
  2276. PSDLINK
  2277. IcaGetPreviousSdLink(
  2278. IN PSDLINK pSdLink
  2279. )
  2280. {
  2281. PLIST_ENTRY Prev;
  2282. PSDLINK pPrevSdLink;
  2283. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  2284. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  2285. ASSERT( pSdLink->RefCount > 0 || pSdLink->Links.Flink == NULL );
  2286. ASSERT( pSdLink->SdContext.pProcedures );
  2287. ASSERT( pSdLink->SdContext.pContext );
  2288. if ( pSdLink->Links.Blink == NULL )
  2289. return( NULL );
  2290. Prev = pSdLink->Links.Blink;
  2291. if ( Prev == &pSdLink->pStack->SdLinkHead )
  2292. return( NULL );
  2293. pPrevSdLink = CONTAINING_RECORD( Prev, SDLINK, Links );
  2294. ASSERT( pPrevSdLink->pStack == pSdLink->pStack );
  2295. ASSERT( pPrevSdLink->RefCount > 0 );
  2296. ASSERT( pPrevSdLink->SdContext.pProcedures );
  2297. ASSERT( pPrevSdLink->SdContext.pContext );
  2298. return( pPrevSdLink );
  2299. }
  2300. VOID
  2301. _IcaReferenceSdLoad(
  2302. IN PSDLOAD pSdLoad
  2303. )
  2304. {
  2305. ASSERT( ExIsResourceAcquiredExclusiveLite( IcaSdLoadResource ) );
  2306. ASSERT( pSdLoad->RefCount >= 0 );
  2307. /*
  2308. * Increment the reference count
  2309. */
  2310. ++pSdLoad->RefCount;
  2311. ASSERT( pSdLoad->RefCount > 0 );
  2312. }
  2313. VOID
  2314. _IcaDereferenceSdLoad(
  2315. IN PSDLOAD pSdLoad
  2316. )
  2317. {
  2318. ASSERT( ExIsResourceAcquiredExclusiveLite( IcaSdLoadResource ) );
  2319. ASSERT( pSdLoad->RefCount > 0 );
  2320. /*
  2321. * Decrement the reference count; if it is 0, unload the SD by queuing
  2322. * a passive level DPC. We must do this to prevent continuing to hold
  2323. * ObpInitKillMutant in the loader -- the driver unload can cause RPC
  2324. * calls which deadlock on that object.
  2325. */
  2326. if ( pSdLoad->RefCount == 1 ) {
  2327. PWORK_QUEUE_ITEM pItem;
  2328. pItem = ICA_ALLOCATE_POOL(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
  2329. if (pItem != NULL) {
  2330. ExInitializeWorkItem(pItem, _IcaUnloadSdWorker, pSdLoad);
  2331. pSdLoad->pUnloadWorkItem = pItem;
  2332. ExQueueWorkItem(pItem, DelayedWorkQueue);
  2333. }
  2334. /* If we cannot allocate workitem do not unload here. It is
  2335. * better to temporarly leak one driver than deadlocking the
  2336. * system.
  2337. */
  2338. }else{
  2339. pSdLoad->RefCount--;
  2340. }
  2341. }
  2342. NTSTATUS IcaExceptionFilter(PWSTR OutputString, PEXCEPTION_POINTERS pexi)
  2343. {
  2344. DbgPrint( "TermDD: %S\n", OutputString );
  2345. DbgPrint( "TermDD: ExceptionRecord=%p ContextRecord=%p\n",
  2346. pexi->ExceptionRecord, pexi->ContextRecord );
  2347. #ifdef i386
  2348. DbgPrint( "TermDD: Exception code=%08x, flags=%08x, addr=%p, IP=%p\n",
  2349. pexi->ExceptionRecord->ExceptionCode,
  2350. pexi->ExceptionRecord->ExceptionFlags,
  2351. pexi->ExceptionRecord->ExceptionAddress,
  2352. pexi->ContextRecord->Eip );
  2353. DbgPrint( "TermDD: esp=%p ebp=%p\n",
  2354. pexi->ContextRecord->Esp, pexi->ContextRecord->Ebp );
  2355. #else
  2356. DbgPrint( "TermDD: Exception code=%08x, flags=%08x, addr=%p\n",
  2357. pexi->ExceptionRecord->ExceptionCode,
  2358. pexi->ExceptionRecord->ExceptionFlags,
  2359. pexi->ExceptionRecord->ExceptionAddress );
  2360. #endif
  2361. {
  2362. SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo;
  2363. NTSTATUS Status;
  2364. Status = ZwQuerySystemInformation(SystemKernelDebuggerInformation,
  2365. &KernelDebuggerInfo, sizeof(KernelDebuggerInfo), NULL);
  2366. if (NT_SUCCESS(Status) && KernelDebuggerInfo.KernelDebuggerEnabled)
  2367. DbgBreakPoint();
  2368. }
  2369. return EXCEPTION_EXECUTE_HANDLER;
  2370. }
  2371. //
  2372. // Helper routine to break if there is a debugger attached
  2373. //
  2374. //
  2375. VOID
  2376. IcaBreakOnDebugger( )
  2377. {
  2378. SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo;
  2379. NTSTATUS Status;
  2380. Status = ZwQuerySystemInformation(SystemKernelDebuggerInformation,
  2381. &KernelDebuggerInfo, sizeof(KernelDebuggerInfo), NULL);
  2382. if (NT_SUCCESS(Status) && KernelDebuggerInfo.KernelDebuggerEnabled)
  2383. DbgBreakPoint();
  2384. }
  2385. /*******************************************************************************
  2386. *
  2387. * _RegisterBrokenEvent
  2388. *
  2389. * Register an event to be signaled when the stack is broken
  2390. *
  2391. * ENTRY:
  2392. * pStack (input)
  2393. * pointer to stack structure
  2394. * pStackBroken (input)
  2395. * pointer to buffer containing event info
  2396. *
  2397. * EXIT:
  2398. * STATUS_SUCCESS - no error
  2399. *
  2400. ******************************************************************************/
  2401. NTSTATUS
  2402. _RegisterBrokenEvent(
  2403. IN PICA_STACK pStack,
  2404. IN PICA_STACK_BROKEN pStackBroken
  2405. )
  2406. {
  2407. NTSTATUS Status;
  2408. /*
  2409. * There should not already be any event registered
  2410. */
  2411. if ( pStack->pBrokenEventObject ) {
  2412. ASSERT( FALSE );
  2413. return( STATUS_OBJECT_NAME_COLLISION );
  2414. }
  2415. /*
  2416. * Reference the event and save a pointer to the object
  2417. */
  2418. Status = ObReferenceObjectByHandle( pStackBroken->BrokenEvent,
  2419. 0L,
  2420. *ExEventObjectType,
  2421. KernelMode,
  2422. (PVOID *)&pStack->pBrokenEventObject,
  2423. NULL
  2424. );
  2425. return( Status );
  2426. }
  2427. /*******************************************************************************
  2428. *
  2429. * _EnablePassthru
  2430. *
  2431. * Enable passthru mode for this connection
  2432. *
  2433. * ENTRY:
  2434. * pStack (input)
  2435. * pointer to passthru stack structure
  2436. *
  2437. * EXIT:
  2438. * STATUS_SUCCESS - no error
  2439. *
  2440. ******************************************************************************/
  2441. NTSTATUS
  2442. _EnablePassthru( PICA_STACK pStack )
  2443. {
  2444. PICA_CONNECTION pConnect;
  2445. PLIST_ENTRY Prev;
  2446. PICA_STACK pPrimaryStack;
  2447. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2448. ASSERT( pStack->pPassthru != NULL );
  2449. ASSERT( !IsListEmpty( &pStack->StackEntry ) );
  2450. /*
  2451. * Lock connection object and get a pointer to it.
  2452. */
  2453. pConnect = IcaLockConnectionForStack( pStack );
  2454. /*
  2455. * Get pointer to previous stack for this connection.
  2456. * If there is one (i.e. prev does not point to the stack head),
  2457. * then it must be the primary stack which we will connect to.
  2458. */
  2459. Prev = pStack->StackEntry.Blink;
  2460. if ( Prev != &pConnect->StackHead ) {
  2461. pPrimaryStack = CONTAINING_RECORD( Prev, ICA_STACK, StackEntry );
  2462. ASSERT( pPrimaryStack->StackClass == Stack_Primary );
  2463. /*
  2464. * Connect the primary and passthru stacks
  2465. */
  2466. pConnect->fPassthruEnabled = TRUE;
  2467. Status = STATUS_SUCCESS;
  2468. }
  2469. IcaUnlockConnection( pConnect );
  2470. return( STATUS_SUCCESS );
  2471. }
  2472. /*******************************************************************************
  2473. *
  2474. * _DisablePassthru
  2475. *
  2476. * Disable passthru mode for this connection
  2477. *
  2478. * ENTRY:
  2479. * pStack (input)
  2480. * pointer to passthru stack structure
  2481. *
  2482. * EXIT:
  2483. * STATUS_SUCCESS - no error
  2484. *
  2485. ******************************************************************************/
  2486. NTSTATUS
  2487. _DisablePassthru(PICA_STACK pStack)
  2488. {
  2489. PICA_CONNECTION pConnect;
  2490. pConnect = IcaLockConnectionForStack(pStack);
  2491. if (pStack->pPassthru) {
  2492. // Lock each stack while clearing the pPassthru pointer.
  2493. // This synchronizes references through the pPassthru pointer
  2494. // within the function IcaRawInputInternal().
  2495. // NOTE: We assume that we have ZERO locks on entry to this function.
  2496. // We then take only one lock at a time so we cannot deadlock.
  2497. IcaLockStack(pStack->pPassthru);
  2498. pStack->pPassthru->pPassthru = NULL;
  2499. IcaUnlockStack(pStack->pPassthru);
  2500. IcaLockStack(pStack);
  2501. pStack->pPassthru = NULL;
  2502. IcaUnlockStack(pStack);
  2503. pConnect->fPassthruEnabled = FALSE;
  2504. }
  2505. IcaUnlockConnection(pConnect);
  2506. return STATUS_SUCCESS;
  2507. }
  2508. /*******************************************************************************
  2509. *
  2510. * _ReconnectStack
  2511. *
  2512. * Reconnect the stack to a new connection object.
  2513. *
  2514. * ENTRY:
  2515. * pStack (input)
  2516. * pointer to stack structure
  2517. *
  2518. * EXIT:
  2519. * STATUS_SUCCESS - no error
  2520. *
  2521. ******************************************************************************/
  2522. NTSTATUS
  2523. _ReconnectStack(PICA_STACK pStack, HANDLE hIca)
  2524. {
  2525. PFILE_OBJECT pNewConnectFileObject;
  2526. PICA_CONNECTION pNewConnect;
  2527. PICA_CONNECTION pOldConnect;
  2528. PLIST_ENTRY pSaveVcBind;
  2529. NTSTATUS Status;
  2530. /*
  2531. * Only allow a reconnect on a Primary stack.
  2532. */
  2533. if ( pStack->StackClass != Stack_Primary )
  2534. return( STATUS_NOT_SUPPORTED );
  2535. /*
  2536. * If passthru mode is enabled, disable it now.
  2537. */
  2538. if ( pStack->pPassthru ) {
  2539. _DisablePassthru( pStack );
  2540. }
  2541. /*
  2542. * Open the file object for the new connection we will attach to.
  2543. */
  2544. Status = ObReferenceObjectByHandle(
  2545. hIca,
  2546. 0L, // DesiredAccess
  2547. *IoFileObjectType,
  2548. KernelMode,
  2549. (PVOID *)&pNewConnectFileObject,
  2550. NULL
  2551. );
  2552. if (!NT_SUCCESS(Status))
  2553. return(Status);
  2554. /*
  2555. * Ensure what we have is a connection object
  2556. */
  2557. if (pNewConnectFileObject->DeviceObject != IcaDeviceObject) {
  2558. ASSERT(FALSE);
  2559. ObDereferenceObject( pNewConnectFileObject );
  2560. return( STATUS_INVALID_PARAMETER );
  2561. }
  2562. /*
  2563. * Get a pointer to the new connection object and reference it.
  2564. */
  2565. pNewConnect = pNewConnectFileObject->FsContext;
  2566. ASSERT( pNewConnect->Header.Type == IcaType_Connection );
  2567. if ( pNewConnect->Header.Type != IcaType_Connection ) {
  2568. ObDereferenceObject( pNewConnectFileObject );
  2569. return( STATUS_INVALID_CONNECTION );
  2570. }
  2571. IcaReferenceConnection(pNewConnect);
  2572. /*
  2573. * Obtain the necessary locks to perform the stack reconnect.
  2574. *
  2575. * First, we acquire the global resource lock.
  2576. *
  2577. * Next lock the connection this stack is currently attached to
  2578. * as well as the new connection the stack will be moved to.
  2579. * NOTE: Because of the use of the global resource lock,
  2580. * there is no possiblility of deadlock even though we
  2581. * are attempting to lock two connection objects at the
  2582. * same time.
  2583. * NOTE: While holding a resource we need to disable APC calls
  2584. * with the CriticalRegion calls.
  2585. *
  2586. * Finally, lock the stack object itself.
  2587. */
  2588. KeEnterCriticalRegion();
  2589. ExAcquireResourceExclusiveLite(IcaReconnectResource, TRUE);
  2590. pOldConnect = IcaLockConnectionForStack(pStack);
  2591. if (pOldConnect == pNewConnect) {
  2592. Status = STATUS_UNSUCCESSFUL;
  2593. goto badoldconnect;
  2594. }
  2595. IcaLockConnection(pNewConnect);
  2596. if (!IsListEmpty(&pNewConnect->VcBindHead)) {
  2597. Status = STATUS_UNSUCCESSFUL;
  2598. goto badnewconnect;
  2599. }
  2600. if (!IsListEmpty(&pNewConnect->StackHead)) {
  2601. PICA_STACK pHeadStack;
  2602. pHeadStack = CONTAINING_RECORD(pStack->StackEntry.Flink, ICA_STACK, StackEntry);
  2603. if (pHeadStack->StackClass == Stack_Primary) {
  2604. Status = STATUS_UNSUCCESSFUL;
  2605. goto badnewconnect;
  2606. }
  2607. }
  2608. IcaLockStack(pStack);
  2609. /*
  2610. * Unbind the virtual channels,
  2611. * and unlink the VcBind list and save a pointer to it
  2612. * (but only if the list is non-empty).
  2613. */
  2614. IcaUnbindVirtualChannels( pOldConnect );
  2615. if ( !IsListEmpty( &pOldConnect->VcBindHead ) ) {
  2616. pSaveVcBind = pOldConnect->VcBindHead.Flink;
  2617. RemoveEntryList( &pOldConnect->VcBindHead );
  2618. InitializeListHead( &pOldConnect->VcBindHead );
  2619. } else {
  2620. pSaveVcBind = NULL;
  2621. }
  2622. /*
  2623. * Unlink this stack from the stack list for this connection,
  2624. * and remove the reference to the Connection object.
  2625. */
  2626. RemoveEntryList( &pStack->StackEntry );
  2627. IcaDereferenceConnection( pOldConnect );
  2628. /*
  2629. * We're done with the old connection object so unlock it now.
  2630. */
  2631. IcaUnlockConnection( pOldConnect );
  2632. /*
  2633. * Restore the VcBind list and Rebind the virtual channels.
  2634. */
  2635. if ( pSaveVcBind ) {
  2636. InsertTailList( pSaveVcBind, &pNewConnect->VcBindHead );
  2637. IcaRebindVirtualChannels( pNewConnect );
  2638. }
  2639. /*
  2640. * Insert this stack in the stack list for this connection,
  2641. * and save the new Connection object pointer for this stack.
  2642. */
  2643. InsertHeadList( &pNewConnect->StackHead, &pStack->StackEntry );
  2644. pStack->pConnect = (PUCHAR)pNewConnect;
  2645. /*
  2646. * Release stack/connection objects and global resource
  2647. */
  2648. IcaUnlockStack( pStack );
  2649. IcaUnlockConnection( pNewConnect );
  2650. ExReleaseResourceLite( IcaReconnectResource );
  2651. KeLeaveCriticalRegion();
  2652. /*
  2653. * The stack requires a connection object reference,
  2654. * so leave the one made above, but dereference the file object.
  2655. */
  2656. //IcaDereferenceConnection( pNewConnect );
  2657. ObDereferenceObject( pNewConnectFileObject );
  2658. return( STATUS_SUCCESS );
  2659. badnewconnect:
  2660. IcaUnlockConnection( pNewConnect );
  2661. badoldconnect:
  2662. IcaUnlockConnection( pOldConnect );
  2663. ExReleaseResourceLite( IcaReconnectResource );
  2664. KeLeaveCriticalRegion();
  2665. IcaDereferenceConnection( pNewConnect );
  2666. ObDereferenceObject( pNewConnectFileObject );
  2667. return( Status );
  2668. }
  2669. PVOID IcaStackAllocatePoolWithTag(
  2670. IN POOL_TYPE PoolType,
  2671. IN SIZE_T NumberOfBytes,
  2672. IN ULONG Tag )
  2673. {
  2674. PVOID pBuffer;
  2675. pBuffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
  2676. if (pBuffer != NULL) {
  2677. gAllocSucceed++;
  2678. } else {
  2679. gAllocFailed++;
  2680. }
  2681. return pBuffer;
  2682. }
  2683. PVOID IcaStackAllocatePool(
  2684. IN POOL_TYPE PoolType,
  2685. IN SIZE_T NumberOfBytes)
  2686. {
  2687. PVOID pBuffer;
  2688. pBuffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, ICA_POOL_TAG);
  2689. if (pBuffer != NULL) {
  2690. gAllocSucceed++;
  2691. } else {
  2692. gAllocFailed++;
  2693. }
  2694. return pBuffer;
  2695. }
  2696. void IcaStackFreePool(IN PVOID Pointer)
  2697. {
  2698. ExFreePool(Pointer);
  2699. gAllocFreed++;
  2700. }
  2701. NTSTATUS _IcaKeepAlive(
  2702. IN BOOLEAN enableKeepAlive,
  2703. IN ULONG interval )
  2704. {
  2705. NTSTATUS status = STATUS_SUCCESS;
  2706. HANDLE ThreadHandle;
  2707. if ( enableKeepAlive )
  2708. {
  2709. // a request has come to start the keep alive thread
  2710. if (pKeepAliveThreadObject == NULL ) // if we have no thread object, thread is not running
  2711. {
  2712. // keep alive thread uses this interval.
  2713. g_KeepAliveInterval = interval;
  2714. // Create a new thread to handle keep alive
  2715. status = PsCreateSystemThread( &ThreadHandle,
  2716. THREAD_ALL_ACCESS,
  2717. NULL,
  2718. NtCurrentProcess(),
  2719. NULL,
  2720. IcaKeepAliveThread,
  2721. NULL );
  2722. if (status == STATUS_SUCCESS) {
  2723. // Reference the thread handle by object
  2724. status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, NULL,
  2725. KernelMode, (PVOID *)&pKeepAliveThreadObject, NULL);
  2726. if (status == STATUS_SUCCESS)
  2727. {
  2728. // KdPrint(("In TermDD: KeepAlive thread created successfully\n"));
  2729. }
  2730. else
  2731. {
  2732. KdPrint(("TermDD: Unable to reference object by thread handle: %d\n", status));
  2733. }
  2734. ZwClose(ThreadHandle);
  2735. }
  2736. else
  2737. {
  2738. KdPrint(("In TermDD: Unable to create KeepAlive thread.\n"));
  2739. }
  2740. }
  2741. else
  2742. {
  2743. // otherwise, keep alive thread is running, but we might have to change the interval to some new value
  2744. // set the new value so that next time around the while loop, it will be picked up.
  2745. g_KeepAliveInterval = interval;
  2746. // KdPrint(("In TermDD: KeepAliveInterval was changes to %d \n",g_KeepAliveInterval ));
  2747. }
  2748. }
  2749. else
  2750. {
  2751. // we don't need the keep alive thread
  2752. if (pKeepAliveThreadObject != NULL )
  2753. {
  2754. // Set IcaKeepAliveEvent to wake up KeepAlive thread
  2755. if (pIcaKeepAliveEvent != NULL )
  2756. {
  2757. KeSetEvent(pIcaKeepAliveEvent, 0, FALSE);
  2758. }
  2759. // Wait for the thread to exit
  2760. KeWaitForSingleObject(pKeepAliveThreadObject, Executive, KernelMode, TRUE, NULL);
  2761. // Deference the thread object
  2762. ObDereferenceObject(pKeepAliveThreadObject);
  2763. pKeepAliveThreadObject = NULL;
  2764. // KdPrint(("In TermDD: KeepAlive thread was terminated successfully \n"));
  2765. status = STATUS_SUCCESS;
  2766. }
  2767. }
  2768. return status;
  2769. }