Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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