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.

2379 lines
71 KiB

  1. /****************************************************************************/
  2. // channel.c
  3. //
  4. // Terminal Server channel handling.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #include <ntddkbd.h>
  11. #include <ntddmou.h>
  12. #include "ptdrvcom.h"
  13. #define min(a,b) (((a) < (b)) ? (a) : (b))
  14. NTSTATUS
  15. IcaExceptionFilter(
  16. IN PWSTR OutputString,
  17. IN PEXCEPTION_POINTERS pexi
  18. );
  19. NTSTATUS
  20. IcaReadChannel (
  21. IN PICA_CHANNEL pChannel,
  22. IN PIRP Irp,
  23. IN PIO_STACK_LOCATION IrpSp
  24. );
  25. NTSTATUS
  26. IcaWriteChannel (
  27. IN PICA_CHANNEL pChannel,
  28. IN PIRP Irp,
  29. IN PIO_STACK_LOCATION IrpSp
  30. );
  31. NTSTATUS
  32. IcaDeviceControlChannel (
  33. IN PICA_CHANNEL pChannel,
  34. IN PIRP Irp,
  35. IN PIO_STACK_LOCATION IrpSp
  36. );
  37. NTSTATUS
  38. IcaFlushChannel (
  39. IN PICA_CHANNEL pChannel,
  40. IN PIRP Irp,
  41. IN PIO_STACK_LOCATION IrpSp
  42. );
  43. NTSTATUS
  44. IcaCleanupChannel (
  45. IN PICA_CHANNEL pChannel,
  46. IN PIRP Irp,
  47. IN PIO_STACK_LOCATION IrpSp
  48. );
  49. NTSTATUS
  50. IcaCloseChannel (
  51. IN PICA_CHANNEL pChannel,
  52. IN PIRP Irp,
  53. IN PIO_STACK_LOCATION IrpSp
  54. );
  55. VOID
  56. IcaFreeAllVcBind(
  57. IN PICA_CONNECTION pConnect
  58. );
  59. NTSTATUS
  60. IcaCancelReadChannel (
  61. IN PICA_CHANNEL pChannel,
  62. IN PIRP Irp,
  63. IN PIO_STACK_LOCATION IrpSp
  64. );
  65. /*
  66. * Local procedure prototypes
  67. */
  68. NTSTATUS
  69. _IcaReadChannelComplete(
  70. IN PICA_CHANNEL pChannel,
  71. IN PIRP Irp,
  72. IN PIO_STACK_LOCATION IrpSp
  73. );
  74. NTSTATUS _IcaQueueReadChannelRequest(
  75. IN PICA_CHANNEL pChannel,
  76. IN PIRP Irp,
  77. IN PIO_STACK_LOCATION IrpSp
  78. );
  79. NTSTATUS
  80. _IcaCopyDataToUserBuffer(
  81. IN PIRP Irp,
  82. IN PUCHAR pBuffer,
  83. IN ULONG ByteCount
  84. );
  85. VOID
  86. _IcaReadChannelCancelIrp(
  87. IN PDEVICE_OBJECT DeviceObject,
  88. IN PIRP Irp
  89. );
  90. VOID _IcaProcessIrpList(
  91. IN PICA_CHANNEL pChannel
  92. );
  93. PICA_CHANNEL
  94. _IcaAllocateChannel(
  95. IN PICA_CONNECTION pConnect,
  96. IN CHANNELCLASS ChannelClass,
  97. IN PVIRTUALCHANNELNAME pVirtualName
  98. );
  99. void _IcaFreeChannel(IN PICA_CHANNEL);
  100. NTSTATUS
  101. _IcaCallStack(
  102. IN PICA_STACK pStack,
  103. IN ULONG ProcIndex,
  104. IN OUT PVOID pParms
  105. );
  106. NTSTATUS
  107. _IcaCallStackNoLock(
  108. IN PICA_STACK pStack,
  109. IN ULONG ProcIndex,
  110. IN OUT PVOID pParms
  111. );
  112. NTSTATUS
  113. _IcaRegisterVcBind(
  114. IN PICA_CONNECTION pConnect,
  115. IN PVIRTUALCHANNELNAME pVirtualName,
  116. IN VIRTUALCHANNELCLASS VirtualClass,
  117. IN ULONG Flags
  118. );
  119. VIRTUALCHANNELCLASS
  120. _IcaFindVcBind(
  121. IN PICA_CONNECTION pConnect,
  122. IN PVIRTUALCHANNELNAME pVirtualName,
  123. OUT PULONG pFlags
  124. );
  125. VOID
  126. _IcaBindChannel(
  127. IN PICA_CHANNEL pChannel,
  128. IN CHANNELCLASS ChannelClass,
  129. IN VIRTUALCHANNELCLASS VirtualClass,
  130. IN ULONG Flags
  131. );
  132. /*
  133. * Dispatch table for ICA channel objects
  134. */
  135. PICA_DISPATCH IcaChannelDispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1] = {
  136. NULL, // IRP_MJ_CREATE
  137. NULL, // IRP_MJ_CREATE_NAMED_PIPE
  138. IcaCloseChannel, // IRP_MJ_CLOSE
  139. IcaReadChannel, // IRP_MJ_READ
  140. IcaWriteChannel, // IRP_MJ_WRITE
  141. NULL, // IRP_MJ_QUERY_INFORMATION
  142. NULL, // IRP_MJ_SET_INFORMATION
  143. NULL, // IRP_MJ_QUERY_EA
  144. NULL, // IRP_MJ_SET_EA
  145. IcaFlushChannel, // IRP_MJ_FLUSH_BUFFERS
  146. NULL, // IRP_MJ_QUERY_VOLUME_INFORMATION
  147. NULL, // IRP_MJ_SET_VOLUME_INFORMATION
  148. NULL, // IRP_MJ_DIRECTORY_CONTROL
  149. NULL, // IRP_MJ_FILE_SYSTEM_CONTROL
  150. IcaDeviceControlChannel, // IRP_MJ_DEVICE_CONTROL
  151. NULL, // IRP_MJ_INTERNAL_DEVICE_CONTROL
  152. NULL, // IRP_MJ_SHUTDOWN
  153. NULL, // IRP_MJ_LOCK_CONTROL
  154. IcaCleanupChannel, // IRP_MJ_CLEANUP
  155. NULL, // IRP_MJ_CREATE_MAILSLOT
  156. NULL, // IRP_MJ_QUERY_SECURITY
  157. NULL, // IRP_MJ_SET_SECURITY
  158. NULL, // IRP_MJ_SET_POWER
  159. NULL, // IRP_MJ_QUERY_POWER
  160. };
  161. #if DBG
  162. extern PICA_DISPATCH IcaStackDispatchTable[];
  163. #endif
  164. NTSTATUS IcaCreateChannel(
  165. IN PICA_CONNECTION pConnect,
  166. IN PICA_OPEN_PACKET openPacket,
  167. IN PIRP Irp,
  168. IN PIO_STACK_LOCATION IrpSp)
  169. /*++
  170. Routine Description:
  171. This routine is called to create a new ICA_CHANNEL object.
  172. - the reference count is incremented by one
  173. Arguments:
  174. pConnect -- pointer to ICA_CONNECTION object
  175. Irp - Pointer to I/O request packet
  176. IrpSp - pointer to the stack location to use for this request.
  177. Return Value:
  178. NTSTATUS -- Indicates whether the request was successfully queued.
  179. --*/
  180. {
  181. PICA_CHANNEL pChannel;
  182. CHANNELCLASS ChannelClass;
  183. NTSTATUS Status;
  184. /*
  185. * Validate ChannelClass
  186. */
  187. ChannelClass = openPacket->TypeInfo.ChannelClass;
  188. if ( !(ChannelClass >= Channel_Keyboard && ChannelClass <= Channel_Virtual) )
  189. return( STATUS_INVALID_PARAMETER );
  190. /*
  191. * Ensure VirtualName has a trailing NULL
  192. */
  193. if ( !memchr( openPacket->TypeInfo.VirtualName,
  194. '\0',
  195. sizeof( openPacket->TypeInfo.VirtualName ) ) )
  196. return( STATUS_INVALID_PARAMETER );
  197. /*
  198. * Must lock connection object to create new channel.
  199. */
  200. IcaLockConnection( pConnect );
  201. TRACE(( pConnect, TC_ICADD, TT_API2, "TermDD: IcaCreateChannel: cc %u, vn %s\n",
  202. ChannelClass, openPacket->TypeInfo.VirtualName ));
  203. /*
  204. * Locate channel object
  205. */
  206. pChannel = IcaFindChannelByName(pConnect,
  207. ChannelClass,
  208. openPacket->TypeInfo.VirtualName);
  209. /*
  210. * See if this channel has already been created.
  211. * If not, then create/initialize it now.
  212. */
  213. if ( pChannel == NULL ) {
  214. /*
  215. * Allocate a new ICA channel object
  216. */
  217. pChannel = _IcaAllocateChannel(pConnect,
  218. ChannelClass,
  219. openPacket->TypeInfo.VirtualName);
  220. if (pChannel == NULL) {
  221. IcaUnlockConnection(pConnect);
  222. return( STATUS_INSUFFICIENT_RESOURCES );
  223. }
  224. }
  225. /*
  226. * Increment open count for this channel
  227. */
  228. if (InterlockedIncrement(&pChannel->OpenCount) <= 0) {
  229. ASSERT( FALSE );
  230. }
  231. /*
  232. * If the CHANNEL_CLOSING flag is set, then we are re-referenceing
  233. * a channel object that was just closed by a previous caller,
  234. * but has not yet been completely dereferenced.
  235. * This can happen if this create call comes in between the
  236. * calls to IcaCleanupChannel and IcaCloseChannel which happen
  237. * when a channel handle is closed.
  238. */
  239. if ( pChannel->Flags & CHANNEL_CLOSING ) {
  240. /*
  241. * Lock channel while we clear out the CHANNEL_CLOSING flag.
  242. */
  243. IcaLockChannel(pChannel);
  244. pChannel->Flags &= ~CHANNEL_CLOSING;
  245. IcaUnlockChannel(pChannel);
  246. }
  247. IcaUnlockConnection(pConnect);
  248. /*
  249. * Save a pointer to the channel in the file object
  250. * so that we can find it in future calls.
  251. * - leave the reference on the channel object
  252. */
  253. IrpSp->FileObject->FsContext = pChannel;
  254. /*
  255. * Exit with the channel reference count incremented by one
  256. */
  257. return STATUS_SUCCESS;
  258. }
  259. NTSTATUS IcaReadChannel(
  260. IN PICA_CHANNEL pChannel,
  261. IN PIRP Irp,
  262. IN PIO_STACK_LOCATION IrpSp)
  263. /*++
  264. Routine Description:
  265. This is the read routine for ICA channels.
  266. Arguments:
  267. pChannel -- pointer to ICA_CHANNEL object
  268. Irp - Pointer to I/O request packet
  269. IrpSp - pointer to the stack location to use for this request.
  270. Return Value:
  271. NTSTATUS -- Indicates whether the request was successfully queued.
  272. --*/
  273. {
  274. KIRQL cancelIrql;
  275. NTSTATUS Status = STATUS_PENDING;
  276. ULONG bChannelAlreadyLocked;
  277. /*
  278. * Determine the channel type to see if read is supported.
  279. * Also do read size verification for keyboard/mouse.
  280. */
  281. switch ( pChannel->ChannelClass ) {
  282. /*
  283. * Make sure input size is a multiple of KEYBOARD_INPUT_DATA
  284. */
  285. case Channel_Keyboard :
  286. if ( IrpSp->Parameters.Read.Length % sizeof(KEYBOARD_INPUT_DATA) )
  287. Status = STATUS_BUFFER_TOO_SMALL;
  288. break;
  289. /*
  290. * Make sure input size is a multiple of MOUSE_INPUT_DATA
  291. */
  292. case Channel_Mouse :
  293. if ( IrpSp->Parameters.Read.Length % sizeof(MOUSE_INPUT_DATA) )
  294. Status = STATUS_BUFFER_TOO_SMALL;
  295. break;
  296. /*
  297. * Nothing required for Command/Virtual channels
  298. */
  299. case Channel_Command :
  300. case Channel_Virtual :
  301. break;
  302. /*
  303. * Read not supported for the following channels
  304. */
  305. case Channel_Video :
  306. case Channel_Beep :
  307. Status = STATUS_INVALID_DEVICE_REQUEST;
  308. break;
  309. default:
  310. ASSERTMSG( "TermDD: Invalid Channel Class", FALSE );
  311. Status = STATUS_INVALID_DEVICE_REQUEST;
  312. break;
  313. }
  314. /*
  315. * If read length is 0, or an error is being returned, return now.
  316. */
  317. if (Status == STATUS_PENDING && IrpSp->Parameters.Read.Length == 0)
  318. Status = STATUS_SUCCESS;
  319. if (Status != STATUS_PENDING) {
  320. Irp->IoStatus.Status = Status;
  321. IoCompleteRequest(Irp, IcaPriorityBoost);
  322. TRACECHANNEL(( pChannel, TC_ICADD, TT_ERROR,
  323. "TermDD: IcaReadChannel, cc %u, vc %d, 0x%x\n",
  324. pChannel->ChannelClass, pChannel->VirtualClass, Status ));
  325. return Status;
  326. }
  327. /*
  328. * Verify user's buffer is valid
  329. */
  330. if (Irp->RequestorMode != KernelMode) {
  331. try {
  332. ProbeForWrite(Irp->UserBuffer, IrpSp->Parameters.Read.Length, sizeof(BYTE));
  333. } except(EXCEPTION_EXECUTE_HANDLER) {
  334. Status = GetExceptionCode();
  335. Irp->IoStatus.Status = Status;
  336. IoCompleteRequest(Irp, IcaPriorityBoost);
  337. TRACECHANNEL((pChannel, TC_ICADD, TT_ERROR,
  338. "TermDD: IcaReadChannel, cc %u, vc %d, 0x%x\n",
  339. pChannel->ChannelClass, pChannel->VirtualClass, Status));
  340. return Status;
  341. }
  342. }
  343. /*
  344. * Lock the channel while we determine how to handle this read request.
  345. * One of the following will be true:
  346. * 1) Input data is available; copy it to user buffer and complete IRP,
  347. * 2) No data available, IRP cancel is requested; cancel/complete IRP,
  348. * 3) No data; add IRP to pending read list, return STATUS_PENDING.
  349. */
  350. if (ExIsResourceAcquiredExclusiveLite(&(pChannel->Resource))) {
  351. bChannelAlreadyLocked = TRUE;
  352. IcaReferenceChannel(pChannel);
  353. }
  354. else {
  355. bChannelAlreadyLocked = FALSE;
  356. IcaLockChannel(pChannel);
  357. }
  358. /*
  359. * If the channel is being closed,
  360. * then don't allow any further read requests.
  361. */
  362. if (pChannel->Flags & CHANNEL_CLOSING) {
  363. Status = STATUS_FILE_CLOSED;
  364. Irp->IoStatus.Status = Status;
  365. IoCompleteRequest(Irp, IcaPriorityBoost);
  366. TRACECHANNEL((pChannel, TC_ICADD, TT_ERROR,
  367. "TermDD: IcaReadChannel, cc %u, vc %d, 0x%x\n",
  368. pChannel->ChannelClass, pChannel->VirtualClass, Status));
  369. IcaUnlockChannel(pChannel);
  370. return Status;
  371. }
  372. /*
  373. * If the Winstation is terminating and Reads are cancelled
  374. * then don't allow any further read requests.
  375. */
  376. if (pChannel->Flags & CHANNEL_CANCEL_READS) {
  377. Status = STATUS_FILE_CLOSED;
  378. Irp->IoStatus.Status = Status;
  379. IoCompleteRequest(Irp, IcaPriorityBoost);
  380. TRACECHANNEL((pChannel, TC_ICADD, TT_ERROR,
  381. "TermDD: IcaReadChannel, cc %u, vc %d, 0x%x\n",
  382. pChannel->ChannelClass, pChannel->VirtualClass, Status));
  383. IcaUnlockChannel(pChannel);
  384. return Status;
  385. }
  386. if (InterlockedCompareExchange(&(pChannel->CompletionRoutineCount), 1, 0) == 0) {
  387. /*
  388. * If there is already input data available,
  389. * then use it to satisfy the caller's read request.
  390. */
  391. if ( !IsListEmpty( &pChannel->InputBufHead ) ) {
  392. _IcaProcessIrpList(pChannel);
  393. if (!IsListEmpty( &pChannel->InputBufHead )) {
  394. Status = _IcaReadChannelComplete( pChannel, Irp, IrpSp );
  395. TRACECHANNEL(( pChannel, TC_ICADD, TT_IN3, "TermDD: IcaReadChannel, cc %u, vc %d, 0x%x\n",
  396. pChannel->ChannelClass, pChannel->VirtualClass, Status ));
  397. _IcaProcessIrpList(pChannel);
  398. }
  399. else {
  400. Status = _IcaQueueReadChannelRequest(pChannel, Irp, IrpSp);
  401. }
  402. }
  403. else {
  404. Status = _IcaQueueReadChannelRequest(pChannel, Irp, IrpSp);
  405. }
  406. InterlockedDecrement(&(pChannel->CompletionRoutineCount));
  407. ASSERT(pChannel->CompletionRoutineCount == 0);
  408. }
  409. else {
  410. Status = _IcaQueueReadChannelRequest(pChannel, Irp, IrpSp);
  411. }
  412. /*
  413. * Unlock channel now
  414. */
  415. if (bChannelAlreadyLocked) {
  416. IcaDereferenceChannel( pChannel );
  417. }
  418. else {
  419. IcaUnlockChannel(pChannel);
  420. }
  421. return Status;
  422. }
  423. void _IcaProcessIrpList(
  424. IN PICA_CHANNEL pChannel)
  425. {
  426. KIRQL cancelIrql;
  427. PIRP irpFromQueue;
  428. PIO_STACK_LOCATION irpSpFromQueue;
  429. PLIST_ENTRY irpQueueHead;
  430. NTSTATUS irpStatus;
  431. ASSERT( ExIsResourceAcquiredExclusiveLite( &pChannel->Resource ) );
  432. /*
  433. * Acquire IoCancel spinlock while checking InputIrp list
  434. */
  435. IoAcquireCancelSpinLock( &cancelIrql );
  436. /*
  437. * If there is a pending read IRP, then remove it from the
  438. * list and try to complete it now.
  439. */
  440. while (!IsListEmpty( &pChannel->InputIrpHead ) &&
  441. !IsListEmpty( &pChannel->InputBufHead )) {
  442. irpQueueHead = RemoveHeadList( &pChannel->InputIrpHead );
  443. irpFromQueue = CONTAINING_RECORD( irpQueueHead, IRP, Tail.Overlay.ListEntry );
  444. irpSpFromQueue = IoGetCurrentIrpStackLocation( irpFromQueue );
  445. /*
  446. * Clear the cancel routine for this IRP
  447. */
  448. IoSetCancelRoutine( irpFromQueue, NULL );
  449. IoReleaseCancelSpinLock( cancelIrql );
  450. irpStatus = _IcaReadChannelComplete( pChannel, irpFromQueue, irpSpFromQueue );
  451. TRACECHANNEL(( pChannel, TC_ICADD, TT_IN3, "TermDD: IcaReadChannel, cc %u, vc %d, 0x%x\n",
  452. pChannel->ChannelClass, pChannel->VirtualClass, irpStatus ));
  453. /*
  454. * Acquire IoCancel spinlock while checking InputIrp list
  455. */
  456. IoAcquireCancelSpinLock( &cancelIrql );
  457. }
  458. IoReleaseCancelSpinLock( cancelIrql );
  459. }
  460. NTSTATUS _IcaQueueReadChannelRequest(
  461. IN PICA_CHANNEL pChannel,
  462. IN PIRP Irp,
  463. IN PIO_STACK_LOCATION IrpSp)
  464. {
  465. KIRQL cancelIrql;
  466. NTSTATUS Status = STATUS_PENDING;
  467. ASSERT( ExIsResourceAcquiredExclusiveLite( &pChannel->Resource ) );
  468. /*
  469. * Acquire the IoCancel spinlock.
  470. * We use this spinlock to protect access to the InputIrp list.
  471. */
  472. IoAcquireCancelSpinLock(&cancelIrql);
  473. /*
  474. * No input data is available.
  475. * Add the Irp to the pending Irp list for this channel.
  476. */
  477. InsertTailList(&pChannel->InputIrpHead, &Irp->Tail.Overlay.ListEntry);
  478. IoMarkIrpPending(Irp);
  479. /*
  480. * If this IRP is being cancelled, then cancel it now.
  481. * Otherwise, set the cancel routine for this request.
  482. */
  483. if (Irp->Cancel) {
  484. Irp->CancelIrql = cancelIrql;
  485. _IcaReadChannelCancelIrp(IrpSp->DeviceObject, Irp);
  486. TRACECHANNEL(( pChannel, TC_ICADD, TT_IN3,
  487. "TermDD: _IcaQueueReadChannelRequest, cc %u, vc %d (canceled)\n",
  488. pChannel->ChannelClass, pChannel->VirtualClass));
  489. return STATUS_CANCELLED;
  490. }
  491. IoSetCancelRoutine(Irp, _IcaReadChannelCancelIrp);
  492. IoReleaseCancelSpinLock(cancelIrql);
  493. TRACECHANNEL((pChannel, TC_ICADD, TT_IN3,
  494. "TermDD: _IcaQueueReadChannelRequest, cc %u, vc %d (pending)\n",
  495. pChannel->ChannelClass, pChannel->VirtualClass));
  496. return STATUS_PENDING;
  497. }
  498. NTSTATUS _IcaReadChannelComplete(
  499. IN PICA_CHANNEL pChannel,
  500. IN PIRP Irp,
  501. IN PIO_STACK_LOCATION IrpSp)
  502. {
  503. KIRQL cancelIrql;
  504. PLIST_ENTRY Head;
  505. PINBUF pInBuf;
  506. PVOID pBuffer;
  507. ULONG CopyCount;
  508. NTSTATUS Status;
  509. ASSERT( ExIsResourceAcquiredExclusiveLite( &pChannel->Resource ) );
  510. TRACECHANNEL(( pChannel, TC_ICADD, TT_IN4, "TermDD: _IcaReadChannelComplete, cc %u, vc %d\n",
  511. pChannel->ChannelClass, pChannel->VirtualClass ));
  512. /*
  513. * Get pointer to first input buffer
  514. */
  515. ASSERT( !IsListEmpty( &pChannel->InputBufHead ) );
  516. Head = pChannel->InputBufHead.Flink;
  517. pInBuf = CONTAINING_RECORD( Head, INBUF, Links );
  518. /*
  519. * Clear the cancel routine for this IRP,
  520. * since one way or the other it will be completed.
  521. */
  522. IoAcquireCancelSpinLock( &cancelIrql );
  523. IoSetCancelRoutine( Irp, NULL );
  524. IoReleaseCancelSpinLock( cancelIrql );
  525. /*
  526. * If this is a message mode channel, all data from a single input
  527. * buffer must fit in the user buffer, otherwise we return an error.
  528. */
  529. if (IrpSp->Parameters.Read.Length < pInBuf->ByteCount &&
  530. (pChannel->Flags & CHANNEL_MESSAGE_MODE)) {
  531. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  532. IoCompleteRequest( Irp, IcaPriorityBoost );
  533. TRACECHANNEL(( pChannel, TC_ICADD, TT_ERROR,
  534. "TermDD: _IcaReadChannelComplete: cc %u, vc %d (buffer too small)\n",
  535. pChannel->ChannelClass, pChannel->VirtualClass ));
  536. return STATUS_BUFFER_TOO_SMALL;
  537. }
  538. /*
  539. * Determine amount of data to copy to user's buffer.
  540. */
  541. CopyCount = min(IrpSp->Parameters.Read.Length, pInBuf->ByteCount);
  542. /*
  543. * Copy input data to user's buffer
  544. */
  545. Status = _IcaCopyDataToUserBuffer(Irp, pInBuf->pBuffer, CopyCount);
  546. /*
  547. * Update ICA buffer pointer and bytes remaining.
  548. * If no bytes remain, then unlink the input buffer and free it.
  549. */
  550. if ( Status == STATUS_SUCCESS ) {
  551. pChannel->InputBufCurSize -= CopyCount;
  552. pInBuf->pBuffer += CopyCount;
  553. pInBuf->ByteCount -= CopyCount;
  554. if ( pInBuf->ByteCount == 0 ) {
  555. RemoveEntryList( &pInBuf->Links );
  556. ICA_FREE_POOL( pInBuf );
  557. }
  558. }
  559. /*
  560. * Mark the Irp complete
  561. */
  562. Irp->IoStatus.Status = Status;
  563. IoCompleteRequest( Irp, IcaPriorityBoost );
  564. TRACECHANNEL(( pChannel, TC_ICADD, TT_IN3,
  565. "TermDD: _IcaReadChannelComplete: cc %u, vc %d, bc %u, 0x%x\n",
  566. pChannel->ChannelClass, pChannel->VirtualClass, CopyCount, Status ));
  567. return Status;
  568. }
  569. NTSTATUS _IcaCopyDataToUserBuffer(
  570. IN PIRP Irp,
  571. IN PUCHAR pBuffer,
  572. IN ULONG ByteCount)
  573. {
  574. NTSTATUS Status;
  575. /*
  576. * If we are in the context of the original caller's process,
  577. * then just copy the data into the user's buffer directly.
  578. */
  579. if ( IoGetRequestorProcess( Irp ) == IoGetCurrentProcess() ) {
  580. try {
  581. Status = STATUS_SUCCESS;
  582. RtlCopyMemory( Irp->UserBuffer, pBuffer, ByteCount );
  583. } except( EXCEPTION_EXECUTE_HANDLER ) {
  584. Status = GetExceptionCode();
  585. }
  586. /*
  587. * If there is a MDL allocated for this IRP, then copy the data
  588. * directly to the users buffer via the MDL.
  589. */
  590. } else if ( Irp->MdlAddress ) {
  591. PVOID UserBuffer;
  592. UserBuffer = MmGetSystemAddressForMdl( Irp->MdlAddress );
  593. try {
  594. if (UserBuffer != NULL) {
  595. Status = STATUS_SUCCESS;
  596. RtlCopyMemory( UserBuffer, pBuffer, ByteCount );
  597. }else {
  598. Status = STATUS_INSUFFICIENT_RESOURCES;
  599. }
  600. } except( EXCEPTION_EXECUTE_HANDLER ) {
  601. Status = GetExceptionCode();
  602. }
  603. /*
  604. * There is no MDL for this request. We must allocate a secondary
  605. * buffer, copy the data to it, and indicate this is a buffered I/O
  606. * request in the IRP. The I/O completion routine will copy the
  607. * data to the user's buffer.
  608. */
  609. } else {
  610. ASSERT( Irp->AssociatedIrp.SystemBuffer == NULL );
  611. Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag( PagedPool,
  612. ByteCount,
  613. ICA_POOL_TAG );
  614. if ( Irp->AssociatedIrp.SystemBuffer == NULL )
  615. return( STATUS_INSUFFICIENT_RESOURCES );
  616. RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, pBuffer, ByteCount );
  617. Irp->Flags |= (IRP_BUFFERED_IO |
  618. IRP_DEALLOCATE_BUFFER |
  619. IRP_INPUT_OPERATION);
  620. Status = STATUS_SUCCESS;
  621. }
  622. if ( Status == STATUS_SUCCESS )
  623. Irp->IoStatus.Information = ByteCount;
  624. return Status;
  625. }
  626. VOID _IcaReadChannelCancelIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  627. {
  628. PIO_STACK_LOCATION IrpSp;
  629. PICA_CHANNEL pChannel;
  630. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  631. pChannel = IrpSp->FileObject->FsContext;
  632. /*
  633. * Remove IRP from channel pending IRP list and release cancel spinlock
  634. */
  635. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  636. IoReleaseCancelSpinLock(Irp->CancelIrql);
  637. /*
  638. * Complete the IRP with a cancellation status code.
  639. */
  640. Irp->IoStatus.Information = 0;
  641. Irp->IoStatus.Status = STATUS_CANCELLED;
  642. IoCompleteRequest(Irp, IcaPriorityBoost);
  643. }
  644. NTSTATUS IcaWriteChannel(
  645. IN PICA_CHANNEL pChannel,
  646. IN PIRP Irp,
  647. IN PIO_STACK_LOCATION IrpSp)
  648. /*++
  649. Routine Description:
  650. This is the write routine for ICA channels.
  651. Arguments:
  652. pChannel -- pointer to ICA_CHANNEL object
  653. Irp - Pointer to I/O request packet. Flags, specific to this
  654. driver, can be specified as a pointer to a ULONG flags value.
  655. The pointer to this value is the first element in the
  656. IRP.Tail.Overlay.DriverContext field.
  657. Currently, only CHANNEL_WRITE_LOWPRIO is supported. Write IRP's with
  658. this flag set will take lower priority than Write IRP's without this
  659. flag set.
  660. IrpSp - pointer to the stack location to use for this request.
  661. Return Value:
  662. NTSTATUS -- Indicates whether the request was successfully queued.
  663. --*/
  664. {
  665. SD_CHANNELWRITE SdWrite;
  666. NTSTATUS Status = STATUS_PENDING;
  667. /*
  668. * Determine the channel type to see if write is supported.
  669. */
  670. switch ( pChannel->ChannelClass ) {
  671. case Channel_Virtual :
  672. if ( pChannel->VirtualClass == UNBOUND_CHANNEL ) {
  673. Status = STATUS_INVALID_DEVICE_REQUEST;
  674. }
  675. break;
  676. /*
  677. * Write not supported for the following channels
  678. */
  679. case Channel_Command :
  680. case Channel_Keyboard :
  681. case Channel_Mouse :
  682. case Channel_Video :
  683. case Channel_Beep :
  684. Status = STATUS_INVALID_DEVICE_REQUEST;
  685. break;
  686. default:
  687. ASSERTMSG( "ICA.SYS: Invalid Channel Class", FALSE );
  688. Status = STATUS_INVALID_DEVICE_REQUEST;
  689. break;
  690. }
  691. /*
  692. * If the channel is being closed,
  693. * then don't allow any further write requests.
  694. */
  695. if ( pChannel->Flags & CHANNEL_CLOSING )
  696. Status = STATUS_FILE_CLOSED;
  697. /*
  698. * If write length is 0, or an error is being returned, return now.
  699. */
  700. if ( Status == STATUS_PENDING && IrpSp->Parameters.Write.Length == 0 )
  701. Status = STATUS_SUCCESS;
  702. if ( Status != STATUS_PENDING ) {
  703. Irp->IoStatus.Status = Status;
  704. IoCompleteRequest( Irp, IcaPriorityBoost );
  705. TRACECHANNEL(( pChannel, TC_ICADD, TT_ERROR, "TermDD: IcaWriteChannel, cc %u, vc %d, 0x%x\n",
  706. pChannel->ChannelClass, pChannel->VirtualClass, Status ));
  707. return( Status );
  708. }
  709. /*
  710. * Verify user's buffer is valid
  711. */
  712. if ( Irp->RequestorMode != KernelMode ) {
  713. try {
  714. ProbeForRead( Irp->UserBuffer, IrpSp->Parameters.Write.Length, sizeof(BYTE) );
  715. } except( EXCEPTION_EXECUTE_HANDLER ) {
  716. Status = GetExceptionCode();
  717. Irp->IoStatus.Status = Status;
  718. IoCompleteRequest( Irp, IcaPriorityBoost );
  719. TRACECHANNEL(( pChannel, TC_ICADD, TT_ERROR, "TermDD: IcaWriteChannel, cc %u, vc %d, 0x%x\n",
  720. pChannel->ChannelClass, pChannel->VirtualClass, Status ));
  721. return( Status );
  722. }
  723. }
  724. /*
  725. * Call the top level stack driver to handle the write
  726. */
  727. SdWrite.ChannelClass = pChannel->ChannelClass;
  728. SdWrite.VirtualClass = pChannel->VirtualClass;
  729. SdWrite.pBuffer = Irp->UserBuffer;
  730. SdWrite.ByteCount = IrpSp->Parameters.Write.Length;
  731. SdWrite.fScreenData = (BOOLEAN)(pChannel->Flags & CHANNEL_SCREENDATA);
  732. SdWrite.fFlags = 0;
  733. /*
  734. * See if the low prio write flag is set in the IRP.
  735. *
  736. * The flags field is passed to termdd.sys via an IRP_MJ_WRITE
  737. * Irp, as a ULONG pointer in the Irp->Tail.Overlay.DriverContext[0] field.
  738. */
  739. if (Irp->Tail.Overlay.DriverContext[0] != NULL) {
  740. ULONG flags = *((ULONG *)Irp->Tail.Overlay.DriverContext[0]);
  741. if (flags & CHANNEL_WRITE_LOWPRIO) {
  742. SdWrite.fFlags |= SD_CHANNELWRITE_LOWPRIO;
  743. }
  744. }
  745. Status = IcaCallDriver( pChannel, SD$CHANNELWRITE, &SdWrite );
  746. /*
  747. * Complete the IRP now since all channel writes are synchronous
  748. * (the user data is captured by the stack driver before returning).
  749. */
  750. Irp->IoStatus.Status = Status;
  751. if ( Status == STATUS_SUCCESS )
  752. Irp->IoStatus.Information = IrpSp->Parameters.Write.Length;
  753. IoCompleteRequest( Irp, IcaPriorityBoost );
  754. TRACECHANNEL(( pChannel, TC_ICADD, TT_OUT3, "TermDD: IcaWriteChannel, cc %u, vc %d, bc %u, 0x%x\n",
  755. pChannel->ChannelClass, pChannel->VirtualClass, SdWrite.ByteCount, Status ));
  756. return Status;
  757. }
  758. NTSTATUS IcaDeviceControlChannel(
  759. IN PICA_CHANNEL pChannel,
  760. IN PIRP Irp,
  761. IN PIO_STACK_LOCATION IrpSp)
  762. {
  763. ULONG code;
  764. PICA_TRACE_BUFFER pTraceBuffer;
  765. NTSTATUS Status;
  766. /*
  767. * If the channel is being closed,
  768. * then don't allow any further requests.
  769. */
  770. if ( pChannel->Flags & CHANNEL_CLOSING )
  771. return( STATUS_FILE_CLOSED );
  772. /*
  773. * Extract the IOCTL control code and process the request.
  774. */
  775. code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  776. #if DBG
  777. if ( code != IOCTL_ICA_CHANNEL_TRACE ) {
  778. TRACECHANNEL(( pChannel, TC_ICADD, TT_API1, "TermDD: IcaDeviceControlChannel, fc %d, ref %u (enter)\n",
  779. (code & 0x3fff) >> 2, pChannel->RefCount ));
  780. }
  781. #endif
  782. /*
  783. * Process generic channel ioctl requests
  784. */
  785. try {
  786. switch ( code ) {
  787. case IOCTL_ICA_CHANNEL_TRACE :
  788. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)(FIELD_OFFSET(ICA_TRACE_BUFFER,Data[0])) )
  789. return( STATUS_BUFFER_TOO_SMALL );
  790. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength > sizeof(ICA_TRACE_BUFFER) )
  791. return( STATUS_INVALID_BUFFER_SIZE );
  792. if ( Irp->RequestorMode != KernelMode ) {
  793. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  794. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  795. sizeof(BYTE) );
  796. }
  797. pTraceBuffer = (PICA_TRACE_BUFFER)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  798. IcaLockConnection( pChannel->pConnect );
  799. IcaTraceFormat( &pChannel->pConnect->TraceInfo,
  800. pTraceBuffer->TraceClass,
  801. pTraceBuffer->TraceEnable,
  802. pTraceBuffer->Data );
  803. IcaUnlockConnection( pChannel->pConnect );
  804. Status = STATUS_SUCCESS;
  805. break;
  806. case IOCTL_ICA_CHANNEL_DISABLE_SESSION_IO:
  807. IcaLockConnection( pChannel->pConnect );
  808. pChannel->Flags |= CHANNEL_SESSION_DISABLEIO;
  809. Status = IcaFlushChannel( pChannel, Irp, IrpSp );
  810. IcaUnlockConnection( pChannel->pConnect );
  811. break;
  812. case IOCTL_ICA_CHANNEL_ENABLE_SESSION_IO:
  813. IcaLockConnection( pChannel->pConnect );
  814. pChannel->Flags &= ~CHANNEL_SESSION_DISABLEIO;
  815. IcaUnlockConnection( pChannel->pConnect );
  816. Status = STATUS_SUCCESS;
  817. break;
  818. case IOCTL_ICA_CHANNEL_CLOSE_COMMAND_CHANNEL :
  819. IcaLockConnection( pChannel->pConnect );
  820. Status = IcaCancelReadChannel(pChannel, Irp, IrpSp);
  821. IcaUnlockConnection( pChannel->pConnect );
  822. break;
  823. case IOCTL_ICA_CHANNEL_ENABLE_SHADOW :
  824. IcaLockConnection( pChannel->pConnect );
  825. pChannel->Flags |= CHANNEL_SHADOW_IO;
  826. IcaUnlockConnection( pChannel->pConnect );
  827. Status = STATUS_SUCCESS;
  828. break;
  829. case IOCTL_ICA_CHANNEL_DISABLE_SHADOW :
  830. IcaLockConnection( pChannel->pConnect );
  831. pChannel->Flags &= ~CHANNEL_SHADOW_IO;
  832. IcaUnlockConnection( pChannel->pConnect );
  833. Status = STATUS_SUCCESS;
  834. break;
  835. case IOCTL_ICA_CHANNEL_END_SHADOW :
  836. {
  837. PLIST_ENTRY Head, Next;
  838. PICA_STACK pStack;
  839. BOOLEAN bShadowEnded = FALSE;
  840. PICA_CHANNEL_END_SHADOW_DATA pData;
  841. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ICA_CHANNEL_END_SHADOW_DATA) ) {
  842. Status = STATUS_INVALID_BUFFER_SIZE;
  843. break;
  844. }
  845. if ( Irp->RequestorMode != KernelMode ) {
  846. ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  847. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  848. sizeof(BYTE) );
  849. }
  850. pData = (PICA_CHANNEL_END_SHADOW_DATA)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  851. /*
  852. * Lock the connection object.
  853. * This will serialize all channel calls for this connection.
  854. */
  855. IcaLockConnection( pChannel->pConnect );
  856. if ( IsListEmpty( &pChannel->pConnect->StackHead ) ) {
  857. IcaUnlockConnection( pChannel->pConnect );
  858. Status = STATUS_INVALID_DEVICE_REQUEST;
  859. break;
  860. }
  861. /*
  862. * Look for shadow stack(s).
  863. */
  864. Head = &pChannel->pConnect->StackHead;
  865. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  866. pStack = CONTAINING_RECORD( Next, ICA_STACK, StackEntry );
  867. /*
  868. * If this is a shadow stack, end it.
  869. */
  870. if ( pStack->StackClass == Stack_Shadow ) {
  871. if ( pStack->pBrokenEventObject ) {
  872. KeSetEvent( pStack->pBrokenEventObject, 0, FALSE );
  873. bShadowEnded = TRUE;
  874. }
  875. }
  876. }
  877. /*
  878. * Unlock the connection object now.
  879. */
  880. IcaUnlockConnection( pChannel->pConnect );
  881. Status = STATUS_SUCCESS;
  882. if (bShadowEnded && pData->bLogError) {
  883. IcaLogError(NULL, pData->StatusCode, NULL, 0, NULL, 0);
  884. }
  885. break;
  886. }
  887. // This IOCTL is not supported by RDP or ICA driver
  888. case IOCTL_VIDEO_ENUM_MONITOR_PDO:
  889. Status = STATUS_DEVICE_NOT_READY;
  890. break;
  891. default :
  892. /*
  893. * Call the appropriate worker routine based on channel type
  894. */
  895. switch ( pChannel->ChannelClass ) {
  896. case Channel_Keyboard :
  897. Status = IcaDeviceControlKeyboard( pChannel, Irp, IrpSp );
  898. break;
  899. case Channel_Mouse :
  900. Status = IcaDeviceControlMouse( pChannel, Irp, IrpSp );
  901. break;
  902. case Channel_Video :
  903. Status = IcaDeviceControlVideo( pChannel, Irp, IrpSp );
  904. break;
  905. case Channel_Beep :
  906. Status = IcaDeviceControlBeep( pChannel, Irp, IrpSp );
  907. break;
  908. case Channel_Virtual :
  909. Status = IcaDeviceControlVirtual( pChannel, Irp, IrpSp );
  910. break;
  911. case Channel_Command :
  912. Status = STATUS_INVALID_DEVICE_REQUEST;
  913. break;
  914. default:
  915. ASSERTMSG( "ICA.SYS: Invalid Channel Class", FALSE );
  916. Status = STATUS_INVALID_DEVICE_REQUEST;
  917. break;
  918. }
  919. }
  920. } except( IcaExceptionFilter( L"IcaDeviceControlChannel TRAPPED!!",
  921. GetExceptionInformation() ) ) {
  922. Status = GetExceptionCode();
  923. }
  924. #if DBG
  925. if ( code != IOCTL_ICA_CHANNEL_TRACE ) {
  926. TRACECHANNEL(( pChannel, TC_ICADD, TT_API1, "TermDD: IcaDeviceControlChannel, fc %d, ref %u, 0x%x\n",
  927. (code & 0x3fff) >> 2, pChannel->RefCount, Status ));
  928. }
  929. #endif
  930. return Status;
  931. }
  932. NTSTATUS IcaFlushChannel(
  933. IN PICA_CHANNEL pChannel,
  934. IN PIRP Irp,
  935. IN PIO_STACK_LOCATION IrpSp)
  936. {
  937. KIRQL cancelIrql;
  938. PLIST_ENTRY Head;
  939. PINBUF pInBuf;
  940. TRACECHANNEL((pChannel, TC_ICADD, TT_API2,
  941. "TermDD: IcaFlushChannel, cc %u, vc %d\n",
  942. pChannel->ChannelClass, pChannel->VirtualClass));
  943. /*
  944. * Lock channel while we flush any input buffers.
  945. */
  946. IcaLockChannel(pChannel);
  947. while (!IsListEmpty( &pChannel->InputBufHead)) {
  948. Head = RemoveHeadList(&pChannel->InputBufHead);
  949. pInBuf = CONTAINING_RECORD(Head, INBUF, Links);
  950. ICA_FREE_POOL(pInBuf);
  951. }
  952. IcaUnlockChannel(pChannel);
  953. return STATUS_SUCCESS;
  954. }
  955. NTSTATUS IcaCleanupChannel(
  956. IN PICA_CHANNEL pChannel,
  957. IN PIRP Irp,
  958. IN PIO_STACK_LOCATION IrpSp)
  959. {
  960. KIRQL cancelIrql;
  961. PLIST_ENTRY Head;
  962. PIRP ReadIrp;
  963. PINBUF pInBuf;
  964. TRACECHANNEL((pChannel, TC_ICADD, TT_API2,
  965. "TermDD: IcaCleanupChannel, cc %u, vc %d\n",
  966. pChannel->ChannelClass, pChannel->VirtualClass));
  967. /*
  968. * Decrement the open count; if it is 0, perform channel cleanup now.
  969. */
  970. ASSERT(pChannel->OpenCount > 0);
  971. if (InterlockedDecrement( &pChannel->OpenCount) == 0) {
  972. /*
  973. * Lock channel while we clear out any
  974. * pending read IRPs and/or input buffers.
  975. */
  976. IcaLockChannel(pChannel);
  977. /*
  978. * Indicate this channel is being closed
  979. */
  980. pChannel->Flags |= CHANNEL_CLOSING;
  981. IoAcquireCancelSpinLock( &cancelIrql );
  982. while ( !IsListEmpty( &pChannel->InputIrpHead ) ) {
  983. Head = pChannel->InputIrpHead.Flink;
  984. ReadIrp = CONTAINING_RECORD( Head, IRP, Tail.Overlay.ListEntry );
  985. ReadIrp->CancelIrql = cancelIrql;
  986. IoSetCancelRoutine( ReadIrp, NULL );
  987. _IcaReadChannelCancelIrp( IrpSp->DeviceObject, ReadIrp );
  988. IoAcquireCancelSpinLock( &cancelIrql );
  989. }
  990. IoReleaseCancelSpinLock( cancelIrql );
  991. while ( !IsListEmpty( &pChannel->InputBufHead ) ) {
  992. Head = RemoveHeadList( &pChannel->InputBufHead );
  993. pInBuf = CONTAINING_RECORD( Head, INBUF, Links );
  994. ICA_FREE_POOL( pInBuf );
  995. }
  996. IcaUnlockChannel(pChannel);
  997. }
  998. return STATUS_SUCCESS;
  999. }
  1000. NTSTATUS IcaCloseChannel(
  1001. IN PICA_CHANNEL pChannel,
  1002. IN PIRP Irp,
  1003. IN PIO_STACK_LOCATION IrpSp)
  1004. {
  1005. PICA_CONNECTION pConnect;
  1006. TRACECHANNEL(( pChannel, TC_ICADD, TT_API2, "TermDD: IcaCloseChannel, cc %u, vc %d, vn %s\n",
  1007. pChannel->ChannelClass, pChannel->VirtualClass, pChannel->VirtualName ));
  1008. pConnect = pChannel->pConnect;
  1009. /*
  1010. * Remove the file object reference for this channel.
  1011. */
  1012. IcaDereferenceChannel(pChannel);
  1013. return STATUS_SUCCESS;
  1014. }
  1015. NTSTATUS IcaChannelInput(
  1016. IN PSDCONTEXT pContext,
  1017. IN CHANNELCLASS ChannelClass,
  1018. IN VIRTUALCHANNELCLASS VirtualClass,
  1019. IN PINBUF pInBuf OPTIONAL,
  1020. IN PUCHAR pBuffer OPTIONAL,
  1021. IN ULONG ByteCount)
  1022. /*++
  1023. Routine Description:
  1024. This is the input (stack callup) routine for ICA channel input.
  1025. Arguments:
  1026. pContext - Pointer to SDCONTEXT for this Stack Driver
  1027. ChannelClass - Channel number for input
  1028. VirtualClass - Virtual channel number for input
  1029. pInBuf - Pointer to INBUF containing data
  1030. pBuffer - Pointer to input data
  1031. NOTE: Either pInBuf OR pBuffer must be specified, but not both.
  1032. ByteCount - length of data in pBuffer
  1033. Return Value:
  1034. NTSTATUS -- Indicates whether the request was handled successfully.
  1035. --*/
  1036. {
  1037. PSDLINK pSdLink;
  1038. PICA_STACK pStack;
  1039. PICA_CONNECTION pConnect;
  1040. NTSTATUS Status;
  1041. /*
  1042. * Use SD passed context to get the SDLINK pointer.
  1043. */
  1044. pSdLink = CONTAINING_RECORD( pContext, SDLINK, SdContext );
  1045. pStack = pSdLink->pStack; // save stack pointer for use below
  1046. pConnect = IcaGetConnectionForStack( pStack );
  1047. ASSERT( pSdLink->pStack->Header.Type == IcaType_Stack );
  1048. ASSERT( pSdLink->pStack->Header.pDispatchTable == IcaStackDispatchTable );
  1049. TRACESTACK(( pStack, TC_ICADD, TT_API1, "TermDD: IcaChannelInput, bc=%u (enter)\n", ByteCount ));
  1050. /*
  1051. * Only the stack object should be locked during input.
  1052. */
  1053. ASSERT( ExIsResourceAcquiredExclusiveLite( &pStack->Resource ) );
  1054. /*
  1055. * Walk up the SDLINK list looking for a driver which has specified
  1056. * a ChannelInput callup routine. If we find one, then call the
  1057. * driver ChannelInput routine to let it handle the call.
  1058. */
  1059. while ( (pSdLink = IcaGetPreviousSdLink( pSdLink )) != NULL ) {
  1060. ASSERT( pSdLink->pStack == pStack );
  1061. if ( pSdLink->SdContext.pCallup->pSdChannelInput ) {
  1062. IcaReferenceSdLink( pSdLink );
  1063. Status = (pSdLink->SdContext.pCallup->pSdChannelInput)(
  1064. pSdLink->SdContext.pContext,
  1065. ChannelClass,
  1066. VirtualClass,
  1067. pInBuf,
  1068. pBuffer,
  1069. ByteCount );
  1070. IcaDereferenceSdLink( pSdLink );
  1071. return Status;
  1072. }
  1073. }
  1074. return IcaChannelInputInternal(pStack, ChannelClass, VirtualClass,
  1075. pInBuf, pBuffer, ByteCount);
  1076. }
  1077. NTSTATUS IcaChannelInputInternal(
  1078. IN PICA_STACK pStack,
  1079. IN CHANNELCLASS ChannelClass,
  1080. IN VIRTUALCHANNELCLASS VirtualClass,
  1081. IN PINBUF pInBuf OPTIONAL,
  1082. IN PCHAR pBuffer OPTIONAL,
  1083. IN ULONG ByteCount)
  1084. {
  1085. PICA_COMMAND_HEADER pHeader;
  1086. PICA_CONNECTION pConnect;
  1087. PICA_CHANNEL pChannel;
  1088. PLIST_ENTRY Head;
  1089. PIRP Irp;
  1090. PIO_STACK_LOCATION IrpSp;
  1091. KIRQL cancelIrql;
  1092. ULONG CopyCount;
  1093. NTSTATUS Status;
  1094. SD_IOCTL SdIoctl;
  1095. TRACESTACK(( pStack, TC_ICADD, TT_API2,
  1096. "TermDD: IcaChannelInputInternal: cc %u, vc %d, bc %u\n",
  1097. ChannelClass, VirtualClass, ByteCount ));
  1098. /*
  1099. * Check for channel command
  1100. */
  1101. switch ( ChannelClass ) {
  1102. case Channel_Keyboard :
  1103. case Channel_Mouse :
  1104. KeQuerySystemTime( &pStack->LastInputTime );
  1105. break;
  1106. case Channel_Command :
  1107. if ( ByteCount < sizeof(ICA_COMMAND_HEADER) ) {
  1108. TRACESTACK(( pStack, TC_ICADD, TT_ERROR,
  1109. "TermDD: IcaChannelInputInternal: Channel_command bad bytecount\n" ));
  1110. break;
  1111. }
  1112. pHeader = (PICA_COMMAND_HEADER) pBuffer;
  1113. switch ( pHeader->Command ) {
  1114. case ICA_COMMAND_BROKEN_CONNECTION :
  1115. TRACESTACK(( pStack, TC_ICADD, TT_API1,
  1116. "TermDD: IcaChannelInputInternal, Broken Connection\n" ));
  1117. /* set closing flag */
  1118. pStack->fClosing = TRUE;
  1119. /*
  1120. * Send cancel i/o to stack drivers
  1121. * - fClosing flag must be set before issuing cancel i/o
  1122. */
  1123. SdIoctl.IoControlCode = IOCTL_ICA_STACK_CANCEL_IO;
  1124. (void) _IcaCallStackNoLock( pStack, SD$IOCTL, &SdIoctl );
  1125. /*
  1126. * If a broken event has been registered for this stack,
  1127. * then signal the event now.
  1128. * NOTE: In this case we exit without forwarding the
  1129. * broken notification to the channel.
  1130. */
  1131. if ( pStack->pBrokenEventObject ) {
  1132. KeSetEvent( pStack->pBrokenEventObject, 0, FALSE );
  1133. ObDereferenceObject( pStack->pBrokenEventObject );
  1134. pStack->pBrokenEventObject = NULL;
  1135. if ( pInBuf )
  1136. ICA_FREE_POOL( pInBuf );
  1137. return( STATUS_SUCCESS );
  1138. }
  1139. break;
  1140. }
  1141. break;
  1142. }
  1143. /*
  1144. * Get the specified channel for this input packet.
  1145. * If not found, we have no choice but to bit-bucket the data.
  1146. */
  1147. pConnect = IcaGetConnectionForStack(pStack);
  1148. pChannel = IcaFindChannel(pConnect, ChannelClass, VirtualClass);
  1149. if (pChannel == NULL) {
  1150. if (pInBuf)
  1151. ICA_FREE_POOL(pInBuf);
  1152. TRACESTACK((pStack, TC_ICADD, TT_ERROR,
  1153. "TermDD: IcaChannelInputInternal: channel not found\n" ));
  1154. return STATUS_SUCCESS;
  1155. }
  1156. /*
  1157. * Lock channel while processing I/O
  1158. */
  1159. IcaLockChannel(pChannel);
  1160. /*
  1161. * If input is from a shadow stack and this channel should not
  1162. * process shadow I/O then bit bucket the data.
  1163. * Do the same if the channel is closing or IO are disabled.
  1164. */
  1165. if ( (pChannel->Flags & (CHANNEL_SESSION_DISABLEIO | CHANNEL_CLOSING)) ||
  1166. (pStack->StackClass == Stack_Shadow &&
  1167. !(pChannel->Flags & CHANNEL_SHADOW_IO)) ) {
  1168. IcaUnlockChannel(pChannel);
  1169. IcaDereferenceChannel(pChannel);
  1170. if (pInBuf)
  1171. ICA_FREE_POOL(pInBuf);
  1172. TRACESTACK((pStack, TC_ICADD, TT_API2,
  1173. "TermDD: IcaChannelInputInternal: shadow or closing channel input\n"));
  1174. return STATUS_SUCCESS;
  1175. }
  1176. /*
  1177. * If input is from an INBUF, initialize pBuffer and ByteCount
  1178. * with values from the buffer header.
  1179. */
  1180. if (pInBuf) {
  1181. pBuffer = pInBuf->pBuffer;
  1182. ByteCount = pInBuf->ByteCount;
  1183. }
  1184. /*
  1185. * If there is a channel filter loaded for this channel,
  1186. * then pass the input data through it before going on.
  1187. */
  1188. if (pChannel->pFilter) {
  1189. PINBUF pFilterBuf;
  1190. pChannel->pFilter->InputFilter(pChannel->pFilter, pBuffer, ByteCount,
  1191. &pFilterBuf);
  1192. if (pInBuf)
  1193. ICA_FREE_POOL(pInBuf);
  1194. /*
  1195. * Refresh INBUF pointer, buffer pointer, and byte count.
  1196. */
  1197. pInBuf = pFilterBuf;
  1198. pBuffer = pInBuf->pBuffer;
  1199. ByteCount = pInBuf->ByteCount;
  1200. }
  1201. /*
  1202. * Process the input data
  1203. */
  1204. while ( ByteCount != 0 ) {
  1205. /*
  1206. * If this is a shadow stack, see if the stack we're shadowing is
  1207. * for a console session
  1208. */
  1209. if (pStack->StackClass == Stack_Shadow)
  1210. {
  1211. PICA_STACK pTopStack;
  1212. PLIST_ENTRY Head, Next;
  1213. Head = &pConnect->StackHead;
  1214. Next = Head->Flink;
  1215. pTopStack = CONTAINING_RECORD( Next, ICA_STACK, StackEntry );
  1216. if (pTopStack->StackClass == Stack_Console)
  1217. {
  1218. /*
  1219. * It is the console, so put on our keyboard/mouse port
  1220. * driver hat and inject the input that way
  1221. */
  1222. if (ChannelClass == Channel_Mouse)
  1223. {
  1224. MOUSE_INPUT_DATA *pmInputData;
  1225. ULONG count;
  1226. pmInputData = (MOUSE_INPUT_DATA *)pBuffer;
  1227. count = ByteCount / sizeof(MOUSE_INPUT_DATA);
  1228. /*
  1229. * This function will always consume all the data
  1230. */
  1231. PtSendCurrentMouseInput(MouDeviceObject, pmInputData, count);
  1232. ByteCount = 0;
  1233. continue;
  1234. }
  1235. else if (ChannelClass == Channel_Keyboard)
  1236. {
  1237. KEYBOARD_INPUT_DATA *pkInputData;
  1238. ULONG count;
  1239. pkInputData = (KEYBOARD_INPUT_DATA *)pBuffer;
  1240. count = ByteCount / sizeof(KEYBOARD_INPUT_DATA);
  1241. /*
  1242. * This function will always consume all the data
  1243. */
  1244. PtSendCurrentKeyboardInput(KbdDeviceObject, pkInputData, count);
  1245. ByteCount = 0;
  1246. continue;
  1247. }
  1248. }
  1249. }
  1250. /*
  1251. * Acquire IoCancel spinlock while checking InputIrp list
  1252. */
  1253. IoAcquireCancelSpinLock( &cancelIrql );
  1254. /*
  1255. * If there is a pending read IRP, then remove it from the
  1256. * list and try to complete it now.
  1257. */
  1258. if ( !IsListEmpty( &pChannel->InputIrpHead ) ) {
  1259. Head = RemoveHeadList( &pChannel->InputIrpHead );
  1260. Irp = CONTAINING_RECORD( Head, IRP, Tail.Overlay.ListEntry );
  1261. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1262. /*
  1263. * Clear the cancel routine for this IRP
  1264. */
  1265. IoSetCancelRoutine( Irp, NULL );
  1266. IoReleaseCancelSpinLock( cancelIrql );
  1267. /*
  1268. * If this is a message mode channel, all data from a single input
  1269. * buffer must fit in the user buffer, otherwise we return an error.
  1270. */
  1271. if ( IrpSp->Parameters.Read.Length < ByteCount &&
  1272. (pChannel->Flags & CHANNEL_MESSAGE_MODE) ) {
  1273. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  1274. IoCompleteRequest( Irp, IcaPriorityBoost );
  1275. TRACECHANNEL(( pChannel, TC_ICADD, TT_API2,
  1276. "TermDD: IcaChannelInputInternal: cc %u, vc %d, (too small)\n",
  1277. ChannelClass, VirtualClass ));
  1278. continue;
  1279. }
  1280. /*
  1281. * Determine amount of data to copy to user's buffer.
  1282. */
  1283. CopyCount = min( IrpSp->Parameters.Read.Length, ByteCount );
  1284. /*
  1285. * Copy input data to user's buffer
  1286. */
  1287. Status = _IcaCopyDataToUserBuffer( Irp, pBuffer, CopyCount );
  1288. /*
  1289. * Mark the Irp complete and return success
  1290. */
  1291. Irp->IoStatus.Status = Status;
  1292. IoCompleteRequest( Irp, IcaPriorityBoost );
  1293. TRACECHANNEL(( pChannel, TC_ICADD, TT_API2,
  1294. "TermDD: IcaChannelInputInternal: cc %u, vc %d, bc %u, 0x%x\n",
  1295. ChannelClass, VirtualClass, CopyCount, Status ));
  1296. /*
  1297. * Update input data pointer and count remaining.
  1298. * Note no need to update pChannel->InputBufCurSize since we never
  1299. * stored this data.
  1300. */
  1301. if ( Status == STATUS_SUCCESS ) {
  1302. pBuffer += CopyCount;
  1303. ByteCount -= CopyCount;
  1304. if ( pInBuf ) {
  1305. pInBuf->pBuffer += CopyCount;
  1306. pInBuf->ByteCount -= CopyCount;
  1307. }
  1308. }
  1309. /*
  1310. * There are no pending IRPs for this channel, so just queue the data.
  1311. */
  1312. } else {
  1313. IoReleaseCancelSpinLock( cancelIrql );
  1314. /*
  1315. * Check to see if we need to discard the data (too much data
  1316. * backed up). This policy only takes effect when the max size
  1317. * is nonzero, which is currently only the case for mouse and
  1318. * keyboard inputs which can withstand being dropped.
  1319. * Note that the read IRPs sent for channels that can have
  1320. * data dropped must request in integral numbers of input
  1321. * blocks -- e.g. a mouse read IRP must have a read buffer size
  1322. * that is a multiple of sizeof(MOUSE_INPUT_DATA). If this is
  1323. * not the case the immediate-copy block above may copy
  1324. * partial input blocks before arriving here.
  1325. */
  1326. if (pChannel->InputBufMaxSize == 0 ||
  1327. (pChannel->InputBufCurSize + ByteCount) <=
  1328. pChannel->InputBufMaxSize) {
  1329. /*
  1330. * If necessary, allocate an input buffer and copy the data
  1331. */
  1332. if (pInBuf == NULL) {
  1333. /*
  1334. * Get input buffer and copy the data
  1335. * If this fails, we have no choice but to bail out.
  1336. */
  1337. pInBuf = ICA_ALLOCATE_POOL(NonPagedPool, sizeof(INBUF) +
  1338. ByteCount);
  1339. if (pInBuf != NULL) {
  1340. pInBuf->ByteCount = ByteCount;
  1341. pInBuf->MaxByteCount = ByteCount;
  1342. pInBuf->pBuffer = (PUCHAR)(pInBuf + 1);
  1343. RtlCopyMemory(pInBuf->pBuffer, pBuffer, ByteCount);
  1344. }
  1345. else {
  1346. break;
  1347. }
  1348. }
  1349. /*
  1350. * Add buffer to tail of input list and clear pInBuf
  1351. * to indicate we have no buffer to free when done.
  1352. */
  1353. InsertTailList( &pChannel->InputBufHead, &pInBuf->Links );
  1354. pChannel->InputBufCurSize += ByteCount;
  1355. pInBuf = NULL;
  1356. /*
  1357. * If any read(s) were posted while we allocated the input
  1358. * buffer, then try to complete as many as possible.
  1359. */
  1360. IoAcquireCancelSpinLock( &cancelIrql );
  1361. while ( !IsListEmpty( &pChannel->InputIrpHead ) &&
  1362. !IsListEmpty( &pChannel->InputBufHead ) ) {
  1363. Head = RemoveHeadList( &pChannel->InputIrpHead );
  1364. Irp = CONTAINING_RECORD( Head, IRP, Tail.Overlay.ListEntry );
  1365. IoSetCancelRoutine( Irp, NULL );
  1366. IoReleaseCancelSpinLock( cancelIrql );
  1367. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1368. Status = _IcaReadChannelComplete( pChannel, Irp, IrpSp );
  1369. IoAcquireCancelSpinLock( &cancelIrql );
  1370. }
  1371. IoReleaseCancelSpinLock( cancelIrql );
  1372. }
  1373. else {
  1374. TRACESTACK(( pStack, TC_ICADD, TT_ERROR,
  1375. "TermDD: IcaChannelInputInternal: Dropped %u bytes "
  1376. "on channelclass %u\n", ByteCount, ChannelClass));
  1377. }
  1378. break;
  1379. }
  1380. }
  1381. /*
  1382. * Unlock channel now
  1383. */
  1384. IcaUnlockChannel(pChannel);
  1385. /*
  1386. * If we still have an INBUF, free it now.
  1387. */
  1388. if (pInBuf)
  1389. ICA_FREE_POOL(pInBuf);
  1390. /*
  1391. * Decrement channel refcount and return
  1392. */
  1393. IcaDereferenceChannel(pChannel);
  1394. return STATUS_SUCCESS;
  1395. }
  1396. /****************************************************************************/
  1397. // IcaFindChannel
  1398. // IcaFindChannelByName
  1399. //
  1400. // Searches for a given channel in the connection channel list, and returns
  1401. // a pointer to it (with an added reference). Returns NULL if not found.
  1402. /****************************************************************************/
  1403. PICA_CHANNEL IcaFindChannel(
  1404. IN PICA_CONNECTION pConnect,
  1405. IN CHANNELCLASS ChannelClass,
  1406. IN VIRTUALCHANNELCLASS VirtualClass)
  1407. {
  1408. PICA_CHANNEL pChannel;
  1409. KIRQL oldIrql;
  1410. NTSTATUS Status;
  1411. /*
  1412. * Ensure we're not looking for an invalid virtual channel number
  1413. */
  1414. ASSERT( ChannelClass != Channel_Virtual ||
  1415. (VirtualClass >= 0 && VirtualClass < VIRTUAL_MAXIMUM) );
  1416. /*
  1417. * If channel does not exist, return NULL.
  1418. */
  1419. IcaLockChannelTable(&pConnect->ChannelTableLock);
  1420. pChannel = pConnect->pChannel[ ChannelClass + VirtualClass ];
  1421. if (pChannel == NULL) {
  1422. TRACE(( pConnect, TC_ICADD, TT_API3,
  1423. "TermDD: IcaFindChannel, cc %u, vc %d (not found)\n",
  1424. ChannelClass, VirtualClass ));
  1425. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1426. return NULL;
  1427. }
  1428. IcaReferenceChannel(pChannel);
  1429. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1430. TRACE((pConnect, TC_ICADD, TT_API3,
  1431. "TermDD: IcaFindChannel, cc %u, vc %d -> %s\n",
  1432. ChannelClass, VirtualClass, pChannel->VirtualName));
  1433. return pChannel;
  1434. }
  1435. PICA_CHANNEL IcaFindChannelByName(
  1436. IN PICA_CONNECTION pConnect,
  1437. IN CHANNELCLASS ChannelClass,
  1438. IN PVIRTUALCHANNELNAME pVirtualName)
  1439. {
  1440. PICA_CHANNEL pChannel;
  1441. PLIST_ENTRY Head, Next;
  1442. ASSERT( ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
  1443. /*
  1444. * If this is not a virtual channel use channel class only
  1445. */
  1446. if (ChannelClass != Channel_Virtual) {
  1447. return IcaFindChannel( pConnect, ChannelClass, 0);
  1448. }
  1449. /*
  1450. * Search the existing channel structures to locate virtual channel name
  1451. */
  1452. IcaLockChannelTable(&pConnect->ChannelTableLock);
  1453. Head = &pConnect->ChannelHead;
  1454. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  1455. pChannel = CONTAINING_RECORD( Next, ICA_CHANNEL, Links );
  1456. if ( (pChannel->ChannelClass == Channel_Virtual) &&
  1457. !_stricmp( pChannel->VirtualName, pVirtualName ) ) {
  1458. break;
  1459. }
  1460. }
  1461. /*
  1462. * If name does not exist, return unbound
  1463. */
  1464. if (Next == Head) {
  1465. TRACE((pConnect, TC_ICADD, TT_API2,
  1466. "TermDD: IcaFindChannelByName: vn %s (not found)\n", pVirtualName));
  1467. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1468. return(NULL);
  1469. }
  1470. IcaReferenceChannel(pChannel);
  1471. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1472. TRACE((pConnect, TC_ICADD, TT_API2,
  1473. "TermDD: IcaFindChannelByName: vn %s, vc %d, ref %u\n",
  1474. pVirtualName, pChannel->VirtualClass,
  1475. (pChannel != NULL ? pChannel->RefCount : 0)));
  1476. return pChannel;
  1477. }
  1478. VOID IcaReferenceChannel(IN PICA_CHANNEL pChannel)
  1479. {
  1480. TRACECHANNEL((pChannel, TC_ICADD, TT_API2,
  1481. "TermDD: IcaReferenceChannel: cc %u, vc %d, ref %u\n",
  1482. pChannel->ChannelClass, pChannel->VirtualClass, pChannel->RefCount));
  1483. ASSERT(pChannel->RefCount >= 0);
  1484. /*
  1485. * Increment the reference count
  1486. */
  1487. if (InterlockedIncrement( &pChannel->RefCount) <= 0) {
  1488. ASSERT(FALSE);
  1489. }
  1490. }
  1491. VOID IcaDereferenceChannel(
  1492. IN PICA_CHANNEL pChannel)
  1493. {
  1494. BOOLEAN bNeedLock = FALSE;
  1495. BOOLEAN bChannelFreed = FALSE;
  1496. PERESOURCE pResource = pChannel->pChannelTableLock;
  1497. PICA_CONNECTION pConnect = pChannel->pConnect;
  1498. TRACECHANNEL((pChannel, TC_ICADD, TT_API2,
  1499. "TermDD: IcaDefeferenceChannel: cc %u, vc %d, ref %u\n",
  1500. pChannel->ChannelClass, pChannel->VirtualClass,
  1501. pChannel->RefCount));
  1502. ASSERT(pChannel->RefCount > 0);
  1503. /*
  1504. * Lock the channel table since a reference going to Zero would cause
  1505. * to change table entry.
  1506. */
  1507. if (pChannel->RefCount == 1) {
  1508. bNeedLock = TRUE;
  1509. IcaLockChannelTable(pResource);
  1510. }
  1511. /*
  1512. * Decrement the reference count; if it is 0, free the channel.
  1513. */
  1514. if (InterlockedDecrement(&pChannel->RefCount) == 0){
  1515. ASSERT(bNeedLock);
  1516. _IcaFreeChannel(pChannel);
  1517. bChannelFreed = TRUE;
  1518. }
  1519. if (bNeedLock) {
  1520. IcaUnlockChannelTable(pResource);
  1521. }
  1522. /*
  1523. * Remove the reference to the Connection object for this channel.
  1524. * moved this here from _IcaFreeChannel because we need to be sure
  1525. * the connection object can't go away before the call to IcaUnlockChannelTable
  1526. * because the connection object is where the channel table locck live.
  1527. */
  1528. if (bChannelFreed) {
  1529. IcaDereferenceConnection(pConnect);
  1530. }
  1531. }
  1532. NTSTATUS IcaBindVirtualChannels(IN PICA_STACK pStack)
  1533. {
  1534. PICA_CONNECTION pConnect;
  1535. PSD_VCBIND pSdVcBind = NULL;
  1536. SD_VCBIND aSdVcBind[ VIRTUAL_MAXIMUM ];
  1537. ULONG SdVcBindCount;
  1538. VIRTUALCHANNELCLASS VirtualClass;
  1539. PICA_CHANNEL pChannel;
  1540. NTSTATUS Status;
  1541. ULONG i, Flags;
  1542. SD_IOCTL SdIoctl;
  1543. pConnect = IcaLockConnectionForStack(pStack);
  1544. SdIoctl.IoControlCode = IOCTL_ICA_VIRTUAL_QUERY_BINDINGS;
  1545. SdIoctl.InputBuffer = NULL;
  1546. SdIoctl.InputBufferLength = 0;
  1547. SdIoctl.OutputBuffer = aSdVcBind;
  1548. SdIoctl.OutputBufferLength = sizeof(aSdVcBind);
  1549. Status = _IcaCallStack(pStack, SD$IOCTL, &SdIoctl);
  1550. if (NT_SUCCESS(Status)) {
  1551. pSdVcBind = &aSdVcBind[0];
  1552. SdVcBindCount = SdIoctl.BytesReturned / sizeof(SD_VCBIND);
  1553. for (i = 0; i < SdVcBindCount; i++, pSdVcBind++) {
  1554. TRACE((pConnect, TC_ICADD, TT_API2,
  1555. "TermDD: IcaBindVirtualChannels: %s -> %d Flags=%x\n",
  1556. pSdVcBind->VirtualName, pSdVcBind->VirtualClass, pSdVcBind->Flags));
  1557. /*
  1558. * Locate virtual class binding
  1559. */
  1560. VirtualClass = _IcaFindVcBind(pConnect, pSdVcBind->VirtualName, &Flags);
  1561. /*
  1562. * If virtual class binding does not exist, create one
  1563. */
  1564. if (VirtualClass == UNBOUND_CHANNEL) {
  1565. /*
  1566. * Allocate a new virtual bind object
  1567. */
  1568. Status = _IcaRegisterVcBind(pConnect, pSdVcBind->VirtualName,
  1569. pSdVcBind->VirtualClass, pSdVcBind->Flags );
  1570. if (!NT_SUCCESS(Status))
  1571. goto PostLockConnection;
  1572. }
  1573. /*
  1574. * Locate channel object
  1575. */
  1576. pChannel = IcaFindChannelByName(pConnect, Channel_Virtual,
  1577. pSdVcBind->VirtualName);
  1578. /*
  1579. * If we found an existing channel object - update it
  1580. */
  1581. if (pChannel != NULL) {
  1582. IcaLockChannel(pChannel);
  1583. _IcaBindChannel(pChannel, Channel_Virtual, pSdVcBind->VirtualClass, pSdVcBind->Flags);
  1584. IcaUnlockChannel(pChannel);
  1585. IcaDereferenceChannel(pChannel);
  1586. }
  1587. }
  1588. }
  1589. PostLockConnection:
  1590. IcaUnlockConnection(pConnect);
  1591. return Status;
  1592. }
  1593. VOID IcaRebindVirtualChannels(IN PICA_CONNECTION pConnect)
  1594. {
  1595. PLIST_ENTRY Head, Next;
  1596. PICA_VCBIND pVcBind;
  1597. PICA_CHANNEL pChannel;
  1598. Head = &pConnect->VcBindHead;
  1599. for (Next = Head->Flink; Next != Head; Next = Next->Flink) {
  1600. pVcBind = CONTAINING_RECORD(Next, ICA_VCBIND, Links);
  1601. /*
  1602. * Locate channel object
  1603. */
  1604. pChannel = IcaFindChannelByName(pConnect, Channel_Virtual,
  1605. pVcBind->VirtualName);
  1606. /*
  1607. * If we found an existing channel object - update it
  1608. */
  1609. if (pChannel != NULL) {
  1610. IcaLockChannel(pChannel);
  1611. _IcaBindChannel(pChannel, Channel_Virtual, pVcBind->VirtualClass, pVcBind->Flags);
  1612. IcaUnlockChannel(pChannel);
  1613. IcaDereferenceChannel(pChannel);
  1614. }
  1615. }
  1616. }
  1617. VOID IcaUnbindVirtualChannels(IN PICA_CONNECTION pConnect)
  1618. {
  1619. PLIST_ENTRY Head, Next;
  1620. PICA_CHANNEL pChannel;
  1621. KIRQL oldIrql;
  1622. /*
  1623. * Loop through the channel list and clear the virtual class
  1624. * for all virtual channels. Also remove the channel pointer
  1625. * from the channel pointers array in the connection object.
  1626. */
  1627. IcaLockChannelTable(&pConnect->ChannelTableLock);
  1628. Head = &pConnect->ChannelHead;
  1629. for (Next = Head->Flink; Next != Head; Next = Next->Flink) {
  1630. pChannel = CONTAINING_RECORD(Next, ICA_CHANNEL, Links);
  1631. if (pChannel->ChannelClass == Channel_Virtual &&
  1632. pChannel->VirtualClass != UNBOUND_CHANNEL) {
  1633. pConnect->pChannel[pChannel->ChannelClass +
  1634. pChannel->VirtualClass] = NULL;
  1635. pChannel->VirtualClass = UNBOUND_CHANNEL;
  1636. }
  1637. }
  1638. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1639. }
  1640. NTSTATUS IcaUnbindVirtualChannel(
  1641. IN PICA_CONNECTION pConnect,
  1642. IN PVIRTUALCHANNELNAME pVirtualName)
  1643. {
  1644. PLIST_ENTRY Head, Next;
  1645. PICA_CHANNEL pChannel;
  1646. PICA_VCBIND pVcBind;
  1647. KIRQL oldIrql;
  1648. /*
  1649. * Loop through the channel list and clear the virtual class
  1650. * for the matching virtual channel. Also remove the channel pointer
  1651. * from the channel pointers array in the connection object.
  1652. */
  1653. IcaLockChannelTable(&pConnect->ChannelTableLock);
  1654. Head = &pConnect->ChannelHead;
  1655. for (Next = Head->Flink; Next != Head; Next = Next->Flink) {
  1656. pChannel = CONTAINING_RECORD(Next, ICA_CHANNEL, Links);
  1657. if (pChannel->ChannelClass == Channel_Virtual &&
  1658. pChannel->VirtualClass != UNBOUND_CHANNEL &&
  1659. !_stricmp( pChannel->VirtualName, pVirtualName)) {
  1660. pConnect->pChannel[pChannel->ChannelClass +
  1661. pChannel->VirtualClass] = NULL;
  1662. pChannel->VirtualClass = UNBOUND_CHANNEL;
  1663. break;
  1664. }
  1665. }
  1666. Head = &pConnect->VcBindHead;
  1667. for (Next = Head->Flink; Next != Head; Next = Next->Flink) {
  1668. pVcBind = CONTAINING_RECORD( Next, ICA_VCBIND, Links );
  1669. if (!_stricmp(pVcBind->VirtualName, pVirtualName)) {
  1670. RemoveEntryList( &pVcBind->Links );
  1671. ICA_FREE_POOL(pVcBind);
  1672. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1673. return STATUS_SUCCESS;
  1674. }
  1675. }
  1676. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1677. return STATUS_OBJECT_NAME_NOT_FOUND;
  1678. }
  1679. PICA_CHANNEL _IcaAllocateChannel(
  1680. IN PICA_CONNECTION pConnect,
  1681. IN CHANNELCLASS ChannelClass,
  1682. IN PVIRTUALCHANNELNAME pVirtualName)
  1683. {
  1684. PICA_CHANNEL pChannel;
  1685. VIRTUALCHANNELCLASS VirtualClass;
  1686. KIRQL oldIrql;
  1687. NTSTATUS Status;
  1688. ULONG Flags;
  1689. ASSERT(ExIsResourceAcquiredExclusiveLite(&pConnect->Resource));
  1690. pChannel = ICA_ALLOCATE_POOL(NonPagedPool, sizeof(*pChannel));
  1691. if (pChannel == NULL)
  1692. return( NULL );
  1693. TRACE((pConnect, TC_ICADD, TT_API2,
  1694. "TermDD: _IcaAllocateChannel: cc %u, vn %s, %x\n",
  1695. ChannelClass, pVirtualName, pChannel));
  1696. RtlZeroMemory(pChannel, sizeof(*pChannel));
  1697. /*
  1698. * Reference the connection object this channel belongs to
  1699. */
  1700. IcaReferenceConnection(pConnect);
  1701. pChannel->pConnect = pConnect;
  1702. pChannel->pChannelTableLock = &pConnect->ChannelTableLock;
  1703. /*
  1704. * Initialize channel reference count to 1;
  1705. * for the file object reference that will be made by the caller.
  1706. */
  1707. pChannel->RefCount = 1;
  1708. pChannel->CompletionRoutineCount = 0;
  1709. /*
  1710. * Initialize the rest of the channel object for non-zero values.
  1711. */
  1712. pChannel->Header.Type = IcaType_Channel;
  1713. pChannel->Header.pDispatchTable = IcaChannelDispatchTable;
  1714. ExInitializeResourceLite(&pChannel->Resource);
  1715. InitializeListHead(&pChannel->InputIrpHead);
  1716. InitializeListHead(&pChannel->InputBufHead);
  1717. IcaLockChannel(pChannel);
  1718. if (ChannelClass == Channel_Virtual) {
  1719. strncpy(pChannel->VirtualName, pVirtualName, VIRTUALCHANNELNAME_LENGTH);
  1720. VirtualClass = _IcaFindVcBind(pConnect, pVirtualName, &Flags);
  1721. } else {
  1722. VirtualClass = 0;
  1723. Flags = 0;
  1724. }
  1725. _IcaBindChannel(pChannel, ChannelClass, VirtualClass, Flags);
  1726. /*
  1727. * Link channel object to connect object
  1728. */
  1729. IcaLockChannelTable(&pConnect->ChannelTableLock);
  1730. InsertHeadList(&pConnect->ChannelHead, &pChannel->Links);
  1731. IcaUnlockChannelTable(&pConnect->ChannelTableLock);
  1732. /*
  1733. * Set channel type specific flags/fields
  1734. * (i.e. shadow I/O is implicitly enabled for the video, beep,
  1735. * and command channels; the command and all virtual channels
  1736. * are message mode channels)
  1737. * Also sets throttling values taken from registry (if appropriate,
  1738. * plus remember a zeromem done to channel struct above).
  1739. */
  1740. switch (ChannelClass) {
  1741. case Channel_Keyboard:
  1742. pChannel->InputBufMaxSize = SysParams.KeyboardThrottleSize;
  1743. break;
  1744. case Channel_Mouse :
  1745. pChannel->InputBufMaxSize = SysParams.MouseThrottleSize;
  1746. break;
  1747. case Channel_Video :
  1748. case Channel_Beep :
  1749. pChannel->Flags |= CHANNEL_SHADOW_IO;
  1750. break;
  1751. case Channel_Command :
  1752. pChannel->Flags |= CHANNEL_SHADOW_IO;
  1753. /* fall through */
  1754. case Channel_Virtual :
  1755. pChannel->Flags |= CHANNEL_MESSAGE_MODE;
  1756. if (!_stricmp( pVirtualName, VIRTUAL_THINWIRE)) {
  1757. pChannel->Flags |= CHANNEL_SCREENDATA;
  1758. }
  1759. break;
  1760. }
  1761. // Per above assert, this function is assumed to be called while the
  1762. // connection lock is held.
  1763. IcaUnlockChannel(pChannel);
  1764. return pChannel;
  1765. }
  1766. void _IcaFreeChannel(IN PICA_CHANNEL pChannel)
  1767. {
  1768. KIRQL oldIrql;
  1769. ASSERT(pChannel->RefCount == 0);
  1770. ASSERT(IsListEmpty(&pChannel->InputIrpHead));
  1771. ASSERT(IsListEmpty(&pChannel->InputBufHead));
  1772. ASSERT(!ExIsResourceAcquiredExclusiveLite(&pChannel->Resource));
  1773. TRACECHANNEL((pChannel, TC_ICADD, TT_API2,
  1774. "TermDD: _IcaFreeChannel: cc %u, vn %s, \n",
  1775. pChannel->ChannelClass, pChannel->VirtualName));
  1776. /*
  1777. * Unlink this channel from the channel list for this connection.
  1778. * this routine must be called with channel table lock held.
  1779. */
  1780. RemoveEntryList(&pChannel->Links);
  1781. if (pChannel->VirtualClass != UNBOUND_CHANNEL) {
  1782. pChannel->pConnect->pChannel[pChannel->ChannelClass + pChannel->VirtualClass] = NULL;
  1783. }
  1784. ExDeleteResourceLite(&pChannel->Resource);
  1785. ICA_FREE_POOL(pChannel);
  1786. }
  1787. NTSTATUS _IcaRegisterVcBind(
  1788. IN PICA_CONNECTION pConnect,
  1789. IN PVIRTUALCHANNELNAME pVirtualName,
  1790. IN VIRTUALCHANNELCLASS VirtualClass,
  1791. IN ULONG Flags)
  1792. {
  1793. PICA_VCBIND pVcBind;
  1794. NTSTATUS Status;
  1795. ASSERT(ExIsResourceAcquiredExclusiveLite(&pConnect->Resource));
  1796. TRACE((pConnect, TC_ICADD, TT_API2,
  1797. "TermDD: _IcaRegisterVcBind: %s -> %d\n",
  1798. pVirtualName, VirtualClass));
  1799. /*
  1800. * Allocate bind structure
  1801. */
  1802. pVcBind = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pVcBind) );
  1803. if (pVcBind != NULL) {
  1804. /*
  1805. * Initialize structure
  1806. */
  1807. RtlZeroMemory(pVcBind, sizeof(*pVcBind));
  1808. strncpy(pVcBind->VirtualName, pVirtualName, VIRTUALCHANNELNAME_LENGTH);
  1809. pVcBind->VirtualClass = VirtualClass;
  1810. pVcBind->Flags = Flags;
  1811. /*
  1812. * Link bind structure to connect object
  1813. */
  1814. InsertHeadList(&pConnect->VcBindHead, &pVcBind->Links);
  1815. return STATUS_SUCCESS;
  1816. }
  1817. else {
  1818. return STATUS_INSUFFICIENT_RESOURCES;
  1819. }
  1820. }
  1821. VOID IcaFreeAllVcBind(IN PICA_CONNECTION pConnect)
  1822. {
  1823. PICA_VCBIND pVcBind;
  1824. PLIST_ENTRY Head;
  1825. TRACE(( pConnect, TC_ICADD, TT_API2, "TermDD: IcaFreeAllVcBind\n" ));
  1826. /*
  1827. * Free all bind structures
  1828. */
  1829. while ( !IsListEmpty( &pConnect->VcBindHead ) ) {
  1830. Head = RemoveHeadList( &pConnect->VcBindHead );
  1831. pVcBind = CONTAINING_RECORD( Head, ICA_VCBIND, Links );
  1832. ICA_FREE_POOL( pVcBind );
  1833. }
  1834. }
  1835. VIRTUALCHANNELCLASS _IcaFindVcBind(
  1836. IN PICA_CONNECTION pConnect,
  1837. IN PVIRTUALCHANNELNAME pVirtualName,
  1838. OUT PULONG pFlags)
  1839. {
  1840. PICA_VCBIND pVcBind;
  1841. PLIST_ENTRY Head, Next;
  1842. ASSERT( ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
  1843. /*
  1844. * Search the existing VC bind structures to locate virtual channel name
  1845. */
  1846. Head = &pConnect->VcBindHead;
  1847. for (Next = Head->Flink; Next != Head; Next = Next->Flink) {
  1848. pVcBind = CONTAINING_RECORD(Next, ICA_VCBIND, Links);
  1849. if (!_stricmp(pVcBind->VirtualName, pVirtualName)) {
  1850. TRACE((pConnect, TC_ICADD, TT_API2,
  1851. "TermDD: _IcaFindVcBind: vn %s -> vc %d\n",
  1852. pVirtualName, pVcBind->VirtualClass));
  1853. *pFlags = pVcBind->Flags;
  1854. return pVcBind->VirtualClass;
  1855. }
  1856. }
  1857. /*
  1858. * If name does not exist, return UNBOUND_CHANNEL
  1859. */
  1860. TRACE(( pConnect, TC_ICADD, TT_API2,
  1861. "TermDD: _IcaFindVcBind: vn %s (not found)\n", pVirtualName ));
  1862. return UNBOUND_CHANNEL;
  1863. }
  1864. VOID _IcaBindChannel(
  1865. IN PICA_CHANNEL pChannel,
  1866. IN CHANNELCLASS ChannelClass,
  1867. IN VIRTUALCHANNELCLASS VirtualClass,
  1868. IN ULONG Flags)
  1869. {
  1870. KIRQL oldIrql;
  1871. ASSERT(ExIsResourceAcquiredExclusiveLite(&pChannel->Resource));
  1872. TRACECHANNEL(( pChannel, TC_ICADD, TT_API2,
  1873. "TermDD: _IcaBindChannel: cc %u, vn %s vc %d\n",
  1874. ChannelClass, pChannel->VirtualName, VirtualClass ));
  1875. pChannel->ChannelClass = ChannelClass;
  1876. pChannel->VirtualClass = VirtualClass;
  1877. IcaLockChannelTable(pChannel->pChannelTableLock);
  1878. if (Flags & SD_CHANNEL_FLAG_SHADOW_PERSISTENT)
  1879. pChannel->Flags |= CHANNEL_SHADOW_PERSISTENT;
  1880. if (VirtualClass != UNBOUND_CHANNEL) {
  1881. ASSERT(pChannel->pConnect->pChannel[ChannelClass + VirtualClass] == NULL);
  1882. pChannel->pConnect->pChannel[ChannelClass + VirtualClass] = pChannel;
  1883. }
  1884. IcaUnlockChannelTable(pChannel->pChannelTableLock);
  1885. }
  1886. BOOLEAN IcaLockChannelTable(PERESOURCE pResource)
  1887. {
  1888. KIRQL oldIrql;
  1889. BOOLEAN Result;
  1890. /*
  1891. * lock the channel object
  1892. */
  1893. KeEnterCriticalRegion(); // Disable APC calls when holding a resource.
  1894. Result = ExAcquireResourceExclusiveLite( pResource, TRUE );
  1895. return Result;
  1896. }
  1897. void IcaUnlockChannelTable(PERESOURCE pResource)
  1898. {
  1899. ExReleaseResourceLite(pResource);
  1900. KeLeaveCriticalRegion(); // Resume APC calls after releasing resource.
  1901. }
  1902. NTSTATUS IcaCancelReadChannel(
  1903. IN PICA_CHANNEL pChannel,
  1904. IN PIRP Irp,
  1905. IN PIO_STACK_LOCATION IrpSp)
  1906. {
  1907. KIRQL cancelIrql;
  1908. PLIST_ENTRY Head;
  1909. PIRP ReadIrp;
  1910. PINBUF pInBuf;
  1911. TRACECHANNEL((pChannel, TC_ICADD, TT_API2,
  1912. "TermDD: IcaCancelReadChannel, cc %u, vc %d\n",
  1913. pChannel->ChannelClass, pChannel->VirtualClass));
  1914. /*
  1915. * Lock channel while we clear out any
  1916. * pending read IRPs and/or input buffers.
  1917. */
  1918. IcaLockChannel(pChannel);
  1919. /*
  1920. * Indicate that Reads are cancelled to this channel
  1921. */
  1922. pChannel->Flags |= CHANNEL_CANCEL_READS;
  1923. IoAcquireCancelSpinLock( &cancelIrql );
  1924. while ( !IsListEmpty( &pChannel->InputIrpHead ) ) {
  1925. Head = pChannel->InputIrpHead.Flink;
  1926. ReadIrp = CONTAINING_RECORD( Head, IRP, Tail.Overlay.ListEntry );
  1927. ReadIrp->CancelIrql = cancelIrql;
  1928. IoSetCancelRoutine( ReadIrp, NULL );
  1929. _IcaReadChannelCancelIrp( IrpSp->DeviceObject, ReadIrp );
  1930. IoAcquireCancelSpinLock( &cancelIrql );
  1931. }
  1932. IoReleaseCancelSpinLock( cancelIrql );
  1933. IcaUnlockChannel(pChannel);
  1934. return STATUS_SUCCESS;
  1935. }