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.

1239 lines
39 KiB

  1. /****************************************************************************/
  2. // tdapi.c
  3. //
  4. // Common code for all Transport Drivers
  5. //
  6. // Typical connection sequence:
  7. //
  8. // TdLoad load driver
  9. // TdOpen open driver (parameters)
  10. // StackCreateEndpoint create new endpoint
  11. // StackConnectionWait establish client connection (endpoint)
  12. // TdClose close driver (does not close endpoint)
  13. // TdUnload unload driver
  14. //
  15. // TdLoad load driver
  16. // TdOpen open driver
  17. // StackOpenEndpoint bind to an existing endpoint
  18. // StackConnectionSend initialize host module data sent to client
  19. //
  20. // (connected session)
  21. //
  22. // StackCloseEndpoint disconnect client connection
  23. // TdClose close driver
  24. // TdUnload unload driver
  25. //
  26. // Copyright (C) 1997-2000 Microsoft Corporation
  27. /****************************************************************************/
  28. #include <ntddk.h>
  29. #include <ntddvdeo.h>
  30. #include <ntddkbd.h>
  31. #include <ntddmou.h>
  32. #include <ntddbeep.h>
  33. #include <winstaw.h>
  34. #include <icadd.h>
  35. #include <sdapi.h>
  36. #include <td.h>
  37. #define REG_GUID_TABLE L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Terminal Server\\lanatable"
  38. #define LANA_ID L"LanaId"
  39. /*=============================================================================
  40. == External Functions Defined
  41. =============================================================================*/
  42. NTSTATUS ModuleEntry( PSDCONTEXT, BOOLEAN );
  43. NTSTATUS TdLoad( PSDCONTEXT );
  44. NTSTATUS TdUnload( PSDCONTEXT );
  45. NTSTATUS TdOpen( PTD, PSD_OPEN );
  46. NTSTATUS TdClose( PTD, PSD_CLOSE );
  47. NTSTATUS TdRawWrite( PTD, PSD_RAWWRITE );
  48. NTSTATUS TdChannelWrite( PTD, PSD_CHANNELWRITE );
  49. NTSTATUS TdSyncWrite( PTD, PSD_SYNCWRITE );
  50. NTSTATUS TdIoctl( PTD, PSD_IOCTL );
  51. /*=============================================================================
  52. == Internal Functions Defined
  53. =============================================================================*/
  54. NTSTATUS _TdInitializeWrite( PTD, POUTBUF );
  55. NTSTATUS _TdWriteCompleteRoutine( PDEVICE_OBJECT, PIRP, PVOID );
  56. VOID _TdWriteCompleteWorker( PTD, PVOID );
  57. /*=============================================================================
  58. == Functions used
  59. =============================================================================*/
  60. NTSTATUS DeviceOpen( PTD, PSD_OPEN );
  61. NTSTATUS DeviceClose( PTD, PSD_CLOSE );
  62. NTSTATUS DeviceInitializeWrite( PTD, POUTBUF );
  63. NTSTATUS DeviceIoctl( PTD, PSD_IOCTL );
  64. NTSTATUS StackCreateEndpoint( PTD, PSD_IOCTL );
  65. NTSTATUS StackCdCreateEndpoint( PTD, PSD_IOCTL );
  66. NTSTATUS StackCallbackInitiate( PTD, PSD_IOCTL );
  67. NTSTATUS StackCallbackComplete( PTD, PSD_IOCTL );
  68. NTSTATUS StackOpenEndpoint( PTD, PSD_IOCTL );
  69. NTSTATUS StackCloseEndpoint( PTD, PSD_IOCTL );
  70. NTSTATUS StackConnectionWait( PTD, PSD_IOCTL );
  71. NTSTATUS StackConnectionSend( PTD, PSD_IOCTL );
  72. NTSTATUS StackConnectionRequest( PTD, PSD_IOCTL );
  73. NTSTATUS StackQueryParams( PTD, PSD_IOCTL );
  74. NTSTATUS StackSetParams( PTD, PSD_IOCTL );
  75. NTSTATUS StackQueryLastError( PTD, PSD_IOCTL );
  76. NTSTATUS StackWaitForStatus( PTD, PSD_IOCTL );
  77. NTSTATUS StackCancelIo( PTD, PSD_IOCTL );
  78. NTSTATUS StackSetBrokenReason( PTD, PSD_IOCTL );
  79. NTSTATUS StackQueryRemoteAddress( PTD, PSD_IOCTL );
  80. VOID OutBufFree( PTD, POUTBUF );
  81. VOID OutBufError( PTD, POUTBUF );
  82. NTSTATUS MemoryAllocate( ULONG, PVOID * );
  83. VOID MemoryFree( PVOID );
  84. /*=============================================================================
  85. == Static global data
  86. =============================================================================*/
  87. /*
  88. * Transport driver procedures
  89. */
  90. PSDPROCEDURE G_pTdProcedures[] =
  91. {
  92. TdOpen,
  93. TdClose,
  94. TdRawWrite,
  95. TdChannelWrite,
  96. TdSyncWrite,
  97. TdIoctl,
  98. };
  99. /*******************************************************************************
  100. * ModuleEntry
  101. *
  102. * ICA driver entry point.
  103. *
  104. * pContext (input/output)
  105. * pointer to the SD context structure
  106. * fLoad (input)
  107. * TRUE - load driver
  108. * FALSE - unload driver
  109. ******************************************************************************/
  110. NTSTATUS ModuleEntry(PSDCONTEXT pContext, BOOLEAN fLoad)
  111. {
  112. if (fLoad)
  113. return TdLoad(pContext);
  114. else
  115. return TdUnload(pContext);
  116. }
  117. /*******************************************************************************
  118. * TdLoad
  119. *
  120. * The ICA driver directly calls this routine immediately after loading
  121. * this transport driver.
  122. *
  123. * 1) initialize procedure dispatch table
  124. * 2) allocate transport driver data structure
  125. ******************************************************************************/
  126. NTSTATUS TdLoad(PSDCONTEXT pContext)
  127. {
  128. NTSTATUS Status;
  129. PTD pTd;
  130. /*
  131. * Initialize td procedures
  132. */
  133. pContext->pProcedures = G_pTdProcedures;
  134. /*
  135. * Since this is the last stack driver there are no callup procedures
  136. */
  137. pContext->pCallup = NULL;
  138. /*
  139. * Allocate TD data structure
  140. */
  141. Status = MemoryAllocate( sizeof(TD), &pTd );
  142. if (Status == STATUS_SUCCESS) {
  143. RtlZeroMemory(pTd, sizeof(TD));
  144. pTd->pContext = pContext;
  145. pContext->pContext = pTd;
  146. }
  147. else {
  148. TRACE((pContext, TC_TD, TT_ERROR, "TdLoad: Failed alloc TD\n"));
  149. }
  150. return Status;
  151. }
  152. /*******************************************************************************
  153. * TdUnload
  154. *
  155. * The ICA driver directly calls this routine immediately after closing
  156. * this transport driver.
  157. *
  158. * 1) free all transport driver data structures
  159. ******************************************************************************/
  160. NTSTATUS TdUnload(PSDCONTEXT pContext)
  161. {
  162. PTD pTd;
  163. /*
  164. * Get pointers to TD data structures
  165. */
  166. pTd = pContext->pContext;
  167. /*
  168. * Free TD private data structures
  169. */
  170. if (pTd->pPrivate)
  171. MemoryFree(pTd->pPrivate);
  172. if (pTd->pAfd)
  173. MemoryFree(pTd->pAfd);
  174. /*
  175. * Free TD data structure
  176. */
  177. MemoryFree(pTd);
  178. /*
  179. * Clear context structure
  180. */
  181. pContext->pContext = NULL;
  182. pContext->pProcedures = NULL;
  183. pContext->pCallup = NULL;
  184. return STATUS_SUCCESS;
  185. }
  186. /*******************************************************************************
  187. * TdOpen
  188. *
  189. * The ICA driver directly calls this routine immediately after loading
  190. * this transport driver.
  191. *
  192. * 1) initialize transport driver parameters
  193. * 2) call device specfic open
  194. * 3) allocate data buffers
  195. *
  196. * ENTRY:
  197. * pTd (input)
  198. * Pointer to TD data structure
  199. * pSdOpen (input/output)
  200. * Points to the parameter structure SD_OPEN.
  201. ******************************************************************************/
  202. NTSTATUS TdOpen(PTD pTd, PSD_OPEN pSdOpen)
  203. {
  204. SD_CLOSE SdClose;
  205. NTSTATUS Status;
  206. /*
  207. * Initialize TD data structure
  208. */
  209. InitializeListHead( &pTd->IoBusyOutBuf );
  210. pTd->InBufCount = 1;
  211. KeInitializeSpinLock( &pTd->InBufListLock );
  212. InitializeListHead( &pTd->InBufBusyHead );
  213. InitializeListHead( &pTd->InBufDoneHead );
  214. InitializeListHead( &pTd->WorkItemHead );
  215. pTd->pClient = pSdOpen->pClient;
  216. pTd->pStatus = pSdOpen->pStatus;
  217. pTd->PdFlag = pSdOpen->PdConfig.Create.PdFlag;
  218. pTd->OutBufLength = pSdOpen->PdConfig.Create.OutBufLength;
  219. pTd->PortNumber = pSdOpen->PdConfig.Create.PortNumber;
  220. pTd->Params = pSdOpen->PdConfig.Params;
  221. pTd->UserBrokenReason = TD_USER_BROKENREASON_UNEXPECTED;
  222. /*
  223. * Open device
  224. */
  225. Status = DeviceOpen(pTd, pSdOpen);
  226. if (NT_SUCCESS(Status)) {
  227. /*
  228. * Save size of header and trailer for td
  229. */
  230. pTd->OutBufHeader = pSdOpen->SdOutBufHeader;
  231. pTd->OutBufTrailer = pSdOpen->SdOutBufTrailer;
  232. KeInitializeEvent(&pTd->SyncWriteEvent, NotificationEvent, FALSE);
  233. TRACE((pTd->pContext, TC_TD, TT_API1, "TdOpen: success\n"));
  234. }
  235. else {
  236. DeviceClose(pTd, &SdClose);
  237. TRACE((pTd->pContext, TC_TD, TT_ERROR, "TdOpen, Status=0x%x\n", Status));
  238. }
  239. return Status;
  240. }
  241. /*******************************************************************************
  242. * TdClose
  243. *
  244. * The ICA driver directly calls this routine immediately before unloading
  245. * this transport driver.
  246. *
  247. * NOTE: This does NOT terminate the client connection
  248. *
  249. * 1) cancel all i/o (returns all OUTBUFs)
  250. * 2) terminate read thread
  251. * 3) free data buffers
  252. * 4) call device specific close
  253. *
  254. * pTd (input)
  255. * Pointer to TD data structure
  256. * pSdClose (input/output)
  257. * Points to the parameter structure SD_CLOSE.
  258. ******************************************************************************/
  259. NTSTATUS TdClose(PTD pTd, PSD_CLOSE pSdClose)
  260. {
  261. NTSTATUS Status;
  262. TRACE((pTd->pContext, TC_TD, TT_API1, "TdClose: (enter)\n"));
  263. /*
  264. * Cancel all pending i/o (read thread)
  265. */
  266. (VOID)StackCancelIo(pTd, NULL);
  267. /*
  268. * Return size of header and trailer for pd
  269. */
  270. pSdClose->SdOutBufHeader = pTd->OutBufHeader;
  271. pSdClose->SdOutBufTrailer = pTd->OutBufTrailer;
  272. /*
  273. * All reads and writes should have previously been canceled
  274. */
  275. ASSERT( pTd->fClosing );
  276. ASSERT( IsListEmpty( &pTd->IoBusyOutBuf ) );
  277. /*
  278. * Wait for input thread to exit
  279. */
  280. if (pTd->pInputThread) {
  281. Status = IcaWaitForSingleObject(pTd->pContext, pTd->pInputThread, 60000);
  282. if ( !NT_SUCCESS(Status) && (Status!=STATUS_CTX_CLOSE_PENDING) ) {
  283. DbgPrint("TdClose: wait for the input thread to exit failed: status=%x pTd=%p\n", Status, pTd);
  284. ASSERT( NT_SUCCESS(Status) || (Status==STATUS_CTX_CLOSE_PENDING) );
  285. }
  286. /*
  287. * Dereference input thread if it hasn't been already
  288. * (it may have been done in StackCallbackComplete while we waited).
  289. */
  290. if (pTd->pInputThread) {
  291. ObDereferenceObject(pTd->pInputThread);
  292. pTd->pInputThread = NULL;
  293. }
  294. }
  295. /*
  296. * Close device
  297. */
  298. Status = DeviceClose(pTd, pSdClose);
  299. TRACE((pTd->pContext, TC_TD, TT_API1, "TdClose: Status=0x%x\n", Status));
  300. return Status;
  301. }
  302. /*******************************************************************************
  303. * _TdInitializeWrite
  304. *
  305. * Initialize the supplied OutBuf and corresponding IRP for writing.
  306. *
  307. * pTd (input)
  308. * Pointer to td data structure
  309. * pOutBuf (input/output)
  310. * Points to the OutBuf to be initialized for writing
  311. ******************************************************************************/
  312. __inline NTSTATUS _TdInitializeWrite(PTD pTd, POUTBUF pOutBuf)
  313. {
  314. PIRP irp = pOutBuf->pIrp;
  315. PIO_STACK_LOCATION irpSp;
  316. NTSTATUS Status;
  317. /*
  318. * Make sure endpoint is open
  319. */
  320. if (pTd->pDeviceObject != NULL) {
  321. // Set current thread for IoSetHardErrorOrVerifyDevice.
  322. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  323. // Get a pointer to the stack location of the first driver which will be
  324. // invoked. This is where the function codes and the parameters are set.
  325. irpSp = IoGetNextIrpStackLocation(irp);
  326. // Set the major function code, file/device objects, and write
  327. // parameters.
  328. irpSp->FileObject = pTd->pFileObject;
  329. irpSp->DeviceObject = pTd->pDeviceObject;
  330. irp->Flags = 0;
  331. return STATUS_SUCCESS;
  332. }
  333. else {
  334. return STATUS_CTX_CLOSE_PENDING;
  335. }
  336. }
  337. /*******************************************************************************
  338. * TdRawWrite
  339. *
  340. * The up stream stack driver calls this routine when it has data
  341. * to write to the transport. This data has all the necessary
  342. * headers and trailers already appended.
  343. *
  344. * The OUTBUF pointed to by this write request must always be
  345. * returned to the up stream stack driver after the write completes
  346. * successfully or unsuccessfully.
  347. *
  348. * 1) call device specific write
  349. * 2) return OUTBUF after write completes (OutBufFree)
  350. * return OUTBUF after an error (OutBufError)
  351. *
  352. * pTd (input)
  353. * Pointer to td data structure
  354. * pSdRawWrite (input)
  355. * Points to the parameter structure SD_RAWWRITE
  356. ******************************************************************************/
  357. NTSTATUS TdRawWrite(PTD pTd, PSD_RAWWRITE pSdRawWrite)
  358. {
  359. POUTBUF pOutBuf;
  360. NTSTATUS Status;
  361. PLIST_ENTRY pWorkItem = NULL;
  362. KIRQL oldIrql;
  363. pOutBuf = pSdRawWrite->pOutBuf;
  364. ASSERT(pOutBuf);
  365. // Check if driver is being closed
  366. if (!pTd->fClosing) {
  367. // See if we have had too many consecutive write errors
  368. if (pTd->WriteErrorCount <= pTd->WriteErrorThreshold) {
  369. // Initialize the IRP contained in the outbuf.
  370. Status = _TdInitializeWrite(pTd, pOutBuf);
  371. if (NT_SUCCESS(Status)) {
  372. // Let the device level code complete the IRP initialization.
  373. Status = DeviceInitializeWrite(pTd, pOutBuf);
  374. if (NT_SUCCESS(Status)) {
  375. // Update the MDL byte count to reflect the exact number
  376. // of bytes to send.
  377. pOutBuf->pMdl->ByteCount = pOutBuf->ByteCount;
  378. // Save our TD structure pointer in the OUTBUF
  379. // so the I/O completion routine can get it.
  380. pOutBuf->pPrivate = pTd;
  381. // Insert outbuf on busy list
  382. InsertTailList(&pTd->IoBusyOutBuf, &pOutBuf->Links);
  383. // Preallocate a completion workitem now and chain it to list of workitems.
  384. Status = IcaAllocateWorkItem(&pWorkItem);
  385. if (!NT_SUCCESS(Status)) {
  386. //
  387. //we inserted the outbuf into the list. In badwrite below,
  388. //we reinitialize this entry and we free it (or return to the pool)
  389. //so, we need to remove this outbuf entry from the list
  390. //
  391. TRACE((pTd->pContext, TC_TD, TT_OUT1,
  392. "TdRawWrite : No memory to allocate WorkItem. Removing Outbuf from the list %04u, %p\n",
  393. pOutBuf->ByteCount, pOutBuf));
  394. RemoveEntryList( &pOutBuf->Links );
  395. goto badwrite;
  396. }
  397. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  398. InsertTailList( &pTd->WorkItemHead, pWorkItem );
  399. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  400. // Register I/O completion routine
  401. if ( pTd->pSelfDeviceObject == NULL ) {
  402. IoSetCompletionRoutine(pOutBuf->pIrp,
  403. _TdWriteCompleteRoutine, pOutBuf, TRUE, TRUE,
  404. TRUE);
  405. } else {
  406. IoSetCompletionRoutineEx(pTd->pSelfDeviceObject,
  407. pOutBuf->pIrp,
  408. _TdWriteCompleteRoutine, pOutBuf, TRUE, TRUE,
  409. TRUE);
  410. }
  411. // Call the device driver
  412. // From this point on we must NOT free the outbuf.
  413. // It will be free'd by the write complete routine.
  414. Status = IoCallDriver(pTd->pDeviceObject, pOutBuf->pIrp);
  415. if (NT_SUCCESS(Status)) {
  416. // Update output counters
  417. pTd->pStatus->Output.Bytes += pOutBuf->ByteCount;
  418. pTd->pStatus->Output.Frames++;
  419. TRACE((pTd->pContext, TC_TD, TT_OUT1,
  420. "TdRawWrite %04u, %08x\n",
  421. pOutBuf->ByteCount, pOutBuf));
  422. TRACEBUF((pTd->pContext, TC_TD, TT_ORAW,
  423. pOutBuf->pBuffer, pOutBuf->ByteCount));
  424. Status = STATUS_SUCCESS;
  425. }
  426. else {
  427. //
  428. //for some reason, IoCallDriver failed (probably a out of memory?)
  429. //in this case, we are leaking the WorkItem and Outbuf because
  430. //we may never a get a call into our completion routine?
  431. //do we need to remove the workitem and outbuf from the list here and free it?
  432. //
  433. goto badcalldriver;
  434. }
  435. }
  436. else {
  437. goto badwrite;
  438. }
  439. }
  440. else {
  441. goto badwrite;
  442. }
  443. }
  444. else {
  445. OutBufError(pTd, pOutBuf);
  446. TRACE((pTd->pContext, TC_TD, TT_API2,
  447. "TdRawWrite: WriteErrorThreshold exceeded\n"));
  448. Status = pTd->LastError;
  449. }
  450. }
  451. else {
  452. OutBufError(pTd, pOutBuf);
  453. TRACE((pTd->pContext, TC_TD, TT_API2, "TdRawWrite: closing\n"));
  454. Status = STATUS_CTX_CLOSE_PENDING;
  455. }
  456. return Status;
  457. /*=============================================================================
  458. == Error returns
  459. =============================================================================*/
  460. /*
  461. * write completed with an error
  462. */
  463. badwrite:
  464. InitializeListHead( &pOutBuf->Links );
  465. OutBufError(pTd, pOutBuf);
  466. /*
  467. * IoCallDriver returned an error
  468. * NOTE: We must NOT free the outbuf here.
  469. * It will be free'd by the write complete routine.
  470. */
  471. badcalldriver:
  472. TRACE(( pTd->pContext, TC_TD, TT_OUT1, "TdRawWrite, Status=0x%x\n", Status ));
  473. pTd->LastError = Status;
  474. pTd->WriteErrorCount++;
  475. pTd->pStatus->Output.TdErrors++;
  476. if (pTd->WriteErrorCount < pTd->WriteErrorThreshold)
  477. Status = STATUS_SUCCESS;
  478. return Status;
  479. }
  480. /*******************************************************************************
  481. * TdChannelWrite - channel write
  482. *
  483. * This routine should never be called
  484. *
  485. * pTd (input)
  486. * Pointer to td data structure
  487. * pSdChannelWrite (input)
  488. * Points to the parameter structure SD_CHANNELWRITE
  489. ******************************************************************************/
  490. NTSTATUS TdChannelWrite(PTD pTd, PSD_CHANNELWRITE pSdChannelWrite)
  491. {
  492. return STATUS_INVALID_DEVICE_REQUEST;
  493. }
  494. /*******************************************************************************
  495. * TdSyncWrite
  496. *
  497. * This routine is called by the up stream stack driver to wait
  498. * for all pending writes to complete.
  499. *
  500. * 1) wait for all writes to complete
  501. * 2) return all OUTBUFs
  502. *
  503. * pTd (input)
  504. * Pointer to td data structure
  505. * pSdFlush (input)
  506. * Points to the parameter structure SD_FLUSH
  507. ******************************************************************************/
  508. NTSTATUS TdSyncWrite(PTD pTd, PSD_SYNCWRITE pSdSyncWrite)
  509. {
  510. NTSTATUS Status;
  511. TRACE(( pTd->pContext, TC_TD, TT_OUT1, "TdSyncWrite (enter)\n" ));
  512. /*
  513. * Return if there are no writes pending
  514. */
  515. if (IsListEmpty(&pTd->IoBusyOutBuf))
  516. return STATUS_SUCCESS;
  517. /*
  518. * Reset sync event and indicate we are waiting
  519. */
  520. if (!pTd->fSyncWriteWaiter) {
  521. pTd->fSyncWriteWaiter = TRUE;
  522. KeResetEvent(&pTd->SyncWriteEvent);
  523. }
  524. /*
  525. * Wait for event to be triggered
  526. */
  527. Status = IcaWaitForSingleObject(pTd->pContext, &pTd->SyncWriteEvent, -1);
  528. if (Status == STATUS_CTX_CLOSE_PENDING)
  529. Status = STATUS_SUCCESS;
  530. TRACE((pTd->pContext, TC_TD, TT_OUT1, "TdSyncWrite (exit)\n"));
  531. return Status;
  532. }
  533. /*******************************************************************************
  534. * TdIoctl
  535. *
  536. * This routine is called by the up stream stack driver. These
  537. * ioctls are used to connect, disconnect, query parameters, and
  538. * set parameters.
  539. *
  540. * pTd (input)
  541. * Pointer to td data structure
  542. * pSdIoctl (input/output)
  543. * Points to the parameter structure SD_IOCTL
  544. ******************************************************************************/
  545. NTSTATUS TdIoctl(PTD pTd, PSD_IOCTL pSdIoctl)
  546. {
  547. NTSTATUS Status;
  548. switch (pSdIoctl->IoControlCode) {
  549. case IOCTL_ICA_STACK_CREATE_ENDPOINT:
  550. Status = StackCreateEndpoint(pTd, pSdIoctl);
  551. break;
  552. case IOCTL_ICA_STACK_OPEN_ENDPOINT:
  553. Status = StackOpenEndpoint(pTd, pSdIoctl);
  554. break;
  555. case IOCTL_ICA_STACK_CLOSE_ENDPOINT:
  556. StackCancelIo(pTd, pSdIoctl);
  557. Status = StackCloseEndpoint(pTd, pSdIoctl);
  558. break;
  559. case IOCTL_ICA_STACK_CONNECTION_WAIT :
  560. Status = StackConnectionWait(pTd, pSdIoctl);
  561. break;
  562. case IOCTL_ICA_STACK_CONNECTION_SEND :
  563. Status = StackConnectionSend(pTd, pSdIoctl);
  564. break;
  565. case IOCTL_ICA_STACK_CONNECTION_REQUEST :
  566. Status = StackConnectionRequest(pTd, pSdIoctl);
  567. break;
  568. case IOCTL_ICA_STACK_QUERY_PARAMS :
  569. Status = StackQueryParams(pTd, pSdIoctl);
  570. break;
  571. case IOCTL_ICA_STACK_SET_PARAMS :
  572. Status = StackSetParams(pTd, pSdIoctl);
  573. break;
  574. case IOCTL_ICA_STACK_QUERY_LAST_ERROR :
  575. Status = StackQueryLastError(pTd, pSdIoctl);
  576. break;
  577. case IOCTL_ICA_STACK_WAIT_FOR_STATUS :
  578. Status = StackWaitForStatus(pTd, pSdIoctl);
  579. break;
  580. case IOCTL_ICA_STACK_CANCEL_IO :
  581. Status = StackCancelIo(pTd, pSdIoctl);
  582. break;
  583. case IOCTL_ICA_STACK_CD_CREATE_ENDPOINT :
  584. Status = StackCdCreateEndpoint(pTd, pSdIoctl);
  585. break;
  586. case IOCTL_ICA_STACK_CALLBACK_INITIATE :
  587. Status = StackCallbackInitiate(pTd, pSdIoctl);
  588. break;
  589. case IOCTL_ICA_STACK_CALLBACK_COMPLETE :
  590. Status = StackCallbackComplete(pTd, pSdIoctl);
  591. break;
  592. case IOCTL_TS_STACK_QUERY_REMOTEADDRESS:
  593. Status = StackQueryRemoteAddress( pTd, pSdIoctl);
  594. break;
  595. case IOCTL_ICA_STACK_QUERY_STATE :
  596. case IOCTL_ICA_STACK_SET_STATE :
  597. case IOCTL_ICA_STACK_ENABLE_DRIVER :
  598. case IOCTL_ICA_STACK_CONNECTION_QUERY :
  599. Status = STATUS_SUCCESS;
  600. break;
  601. case IOCTL_ICA_STACK_SET_BROKENREASON:
  602. Status = StackSetBrokenReason(pTd, pSdIoctl);
  603. break;
  604. default:
  605. Status = DeviceIoctl(pTd, pSdIoctl);
  606. break;
  607. }
  608. TRACE((pTd->pContext, TC_TD, TT_API1, "TdIoctl(0x%08x): Status=0x%08x\n",
  609. pSdIoctl->IoControlCode, Status));
  610. return Status;
  611. }
  612. /*******************************************************************************
  613. * _TdWriteCompleteRoutine
  614. *
  615. * This routine is called at DPC level by the lower level device
  616. * driver when an IRP corresponding to an outbuf is completed.
  617. *
  618. * DeviceObject (input)
  619. * not used
  620. * pIrp (input)
  621. * pointer to IRP that is complete
  622. * Context (input)
  623. * Context pointer setup when IRP was initialized.
  624. * This is a pointer to the corresponding outbuf.
  625. ******************************************************************************/
  626. NTSTATUS _TdWriteCompleteRoutine(
  627. IN PDEVICE_OBJECT DeviceObject,
  628. IN PIRP Irp,
  629. IN PVOID Context)
  630. {
  631. POUTBUF pOutBuf = (POUTBUF)Context;
  632. PTD pTd = (PTD)pOutBuf->pPrivate;
  633. PLIST_ENTRY pWorkItem;
  634. KIRQL oldIrql;
  635. // To prevent the OutBuf associated IRP from being canceled by
  636. // DeviceCancelIo between queuing the PASSIVE_LEVEL work item below
  637. // and the actual processing, set the completed flag.
  638. pOutBuf->fIrpCompleted = TRUE;
  639. /*
  640. * Unqueue one of the pre-allocated workitems and use it
  641. * to queue the completion worker.
  642. */
  643. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  644. ASSERT(!IsListEmpty(&pTd->WorkItemHead));
  645. pWorkItem = pTd->WorkItemHead.Flink;
  646. RemoveEntryList(pWorkItem);
  647. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  648. /*
  649. * Queue the outbuf completion processing to a worker thread
  650. * since we are not in the correct context to do it here.
  651. */
  652. IcaQueueWorkItemEx( pTd->pContext, _TdWriteCompleteWorker, Context,
  653. ICALOCK_DRIVER, pWorkItem );
  654. /*
  655. * We return STATUS_MORE_PROCESS_REQUIRED so that no further
  656. * processing for this IRP is done by the I/O completion routine.
  657. */
  658. return STATUS_MORE_PROCESSING_REQUIRED;
  659. }
  660. /*******************************************************************************
  661. * _TdWriteCompleteWorker
  662. *
  663. * This routine is called by an ExWorker thread to complete processing
  664. * on an outbuf. We will release the outbuf and trigger the syncwrite
  665. * event if anyone is waiting.
  666. *
  667. * pTd (input)
  668. * Pointer to td data structure
  669. * Context (input)
  670. * Context pointer setup when IRP was initialized.
  671. * This is a pointer to the corresponding outbuf.
  672. ******************************************************************************/
  673. void _TdWriteCompleteWorker(IN PTD pTd, IN PVOID Context)
  674. {
  675. POUTBUF pOutBuf = (POUTBUF)Context;
  676. PIRP pIrp = pOutBuf->pIrp;
  677. NTSTATUS Status;
  678. TRACE(( pTd->pContext, TC_TD, TT_API3, "_TdWriteCompleteWorker: %08x\n", pOutBuf ));
  679. /*
  680. * Unlink outbuf from busy list
  681. */
  682. RemoveEntryList( &pOutBuf->Links );
  683. InitializeListHead( &pOutBuf->Links );
  684. //
  685. // Check to see whether any pages need to be unlocked.
  686. //
  687. if (pIrp->MdlAddress != NULL) {
  688. PMDL mdl, thisMdl;
  689. // Unlock any pages that may be described by MDLs.
  690. mdl = pIrp->MdlAddress;
  691. while (mdl != NULL) {
  692. thisMdl = mdl;
  693. mdl = mdl->Next;
  694. if (thisMdl == pOutBuf->pMdl)
  695. continue;
  696. MmUnlockPages( thisMdl );
  697. IoFreeMdl( thisMdl );
  698. }
  699. }
  700. /*
  701. * Any MDL we set in DeviceInitializeWrite() is part of the OUTBUF.
  702. */
  703. pIrp->MdlAddress = NULL;
  704. // Check for IRP cancellation and success.
  705. if (!pIrp->Cancel && NT_SUCCESS(pIrp->IoStatus.Status)) {
  706. // Clear the consecutive error count and complete the outbuf by
  707. // calling OutBufFree.
  708. pTd->WriteErrorCount = 0;
  709. OutBufFree(pTd, pOutBuf);
  710. }
  711. else {
  712. // If IRP was cancelled or completed with a failure status,
  713. // then increment the error counts and call OutBufError.
  714. if (pIrp->Cancel)
  715. pTd->LastError = (ULONG)STATUS_CANCELLED;
  716. else
  717. pTd->LastError = pIrp->IoStatus.Status;
  718. pTd->WriteErrorCount++;
  719. pTd->pStatus->Output.TdErrors++;
  720. OutBufError(pTd, pOutBuf);
  721. }
  722. /*
  723. * If there is a waiter in TdSyncWrite and the outbuf busy list
  724. * is now empty, then satisfy the wait now.
  725. */
  726. if (pTd->fSyncWriteWaiter && IsListEmpty(&pTd->IoBusyOutBuf)) {
  727. pTd->fSyncWriteWaiter = FALSE;
  728. KeSetEvent(&pTd->SyncWriteEvent, 1, FALSE);
  729. }
  730. }
  731. NTSTATUS _OpenRegKey(PHANDLE HandlePtr, PWCHAR KeyName)
  732. /*++
  733. Opens a Registry key and returns a handle to it.
  734. Arguments:
  735. HandlePtr - The varible into which to write the opened handle.
  736. KeyName - The name of the Registry key to open.
  737. --*/
  738. {
  739. OBJECT_ATTRIBUTES ObjectAttributes;
  740. UNICODE_STRING UKeyName;
  741. PAGED_CODE();
  742. RtlInitUnicodeString(&UKeyName, KeyName);
  743. memset(&ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  744. InitializeObjectAttributes(&ObjectAttributes, &UKeyName,
  745. OBJ_CASE_INSENSITIVE, NULL, NULL);
  746. return ZwOpenKey(HandlePtr, KEY_READ, &ObjectAttributes);
  747. }
  748. NTSTATUS _GetRegDWORDValue(HANDLE KeyHandle, PWCHAR ValueName, PULONG ValueData)
  749. /*++
  750. Reads a REG_DWORD value from the registry into the supplied variable.
  751. Arguments:
  752. KeyHandle - Open handle to the parent key of the value to read.
  753. ValueName - The name of the value to read.
  754. ValueData - The variable into which to read the data.
  755. --*/
  756. {
  757. NTSTATUS status;
  758. ULONG resultLength;
  759. PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
  760. #define WORK_BUFFER_SIZE 512
  761. UCHAR keybuf[WORK_BUFFER_SIZE];
  762. UNICODE_STRING UValueName;
  763. RtlInitUnicodeString(&UValueName, ValueName);
  764. keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf;
  765. RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
  766. status = ZwQueryValueKey(KeyHandle,
  767. &UValueName,
  768. KeyValueFullInformation,
  769. keyValueFullInformation,
  770. WORK_BUFFER_SIZE,
  771. &resultLength);
  772. if (NT_SUCCESS(status)) {
  773. if (keyValueFullInformation->Type != REG_DWORD) {
  774. status = STATUS_INVALID_PARAMETER_MIX;
  775. } else {
  776. *ValueData = *((ULONG UNALIGNED *)((PCHAR)keyValueFullInformation +
  777. keyValueFullInformation->DataOffset));
  778. }
  779. }
  780. return status;
  781. }
  782. NTSTATUS _GetRegStringValue(
  783. HANDLE KeyHandle,
  784. PWCHAR ValueName,
  785. PKEY_VALUE_PARTIAL_INFORMATION *ValueData,
  786. PUSHORT ValueSize)
  787. /*++
  788. Reads a REG_*_SZ string value from the Registry into the supplied
  789. key value buffer. If the buffer string buffer is not large enough,
  790. it is reallocated.
  791. Arguments:
  792. KeyHandle - Open handle to the parent key of the value to read.
  793. ValueName - The name of the value to read.
  794. ValueData - Destination for the read data.
  795. ValueSize - Size of the ValueData buffer. Updated on output.
  796. --*/
  797. {
  798. NTSTATUS status;
  799. ULONG resultLength;
  800. UNICODE_STRING UValueName;
  801. PAGED_CODE();
  802. RtlInitUnicodeString(&UValueName, ValueName);
  803. status = ZwQueryValueKey(
  804. KeyHandle,
  805. &UValueName,
  806. KeyValuePartialInformation,
  807. *ValueData,
  808. (ULONG) *ValueSize,
  809. &resultLength);
  810. if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) {
  811. PVOID temp;
  812. // Free the old buffer and allocate a new one of the
  813. // appropriate size.
  814. ASSERT(resultLength > (ULONG) *ValueSize);
  815. if (resultLength <= 0xFFFF) {
  816. status = MemoryAllocate(resultLength, &temp);
  817. if (status != STATUS_SUCCESS)
  818. return status;
  819. if (*ValueData != NULL)
  820. MemoryFree(*ValueData);
  821. *ValueData = temp;
  822. *ValueSize = (USHORT) resultLength;
  823. status = ZwQueryValueKey(KeyHandle,
  824. &UValueName,
  825. KeyValuePartialInformation,
  826. *ValueData,
  827. *ValueSize,
  828. &resultLength);
  829. ASSERT((status != STATUS_BUFFER_OVERFLOW) &&
  830. (status != STATUS_BUFFER_TOO_SMALL));
  831. }
  832. else {
  833. status = STATUS_BUFFER_TOO_SMALL;
  834. }
  835. }
  836. return status;
  837. }
  838. NTSTATUS _GetRegMultiSZValue(
  839. HANDLE KeyHandle,
  840. PWCHAR ValueName,
  841. PUNICODE_STRING ValueData)
  842. /*++
  843. Reads a REG_MULTI_SZ string value from the Registry into the supplied
  844. Unicode string. If the Unicode string buffer is not large enough,
  845. it is reallocated.
  846. Arguments:
  847. KeyHandle - Open handle to the parent key of the value to read.
  848. ValueName - The name of the value to read.
  849. ValueData - Destination Unicode string for the value data.
  850. --*/
  851. {
  852. NTSTATUS status;
  853. ULONG resultLength;
  854. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  855. UNICODE_STRING UValueName;
  856. PAGED_CODE();
  857. ValueData->Length = 0;
  858. status = _GetRegStringValue(
  859. KeyHandle,
  860. ValueName,
  861. (PKEY_VALUE_PARTIAL_INFORMATION *) &(ValueData->Buffer),
  862. &(ValueData->MaximumLength));
  863. if (NT_SUCCESS(status)) {
  864. keyValuePartialInformation =
  865. (PKEY_VALUE_PARTIAL_INFORMATION)ValueData->Buffer;
  866. if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
  867. ValueData->Length = (USHORT)
  868. keyValuePartialInformation->DataLength;
  869. RtlCopyMemory(
  870. ValueData->Buffer,
  871. &(keyValuePartialInformation->Data),
  872. ValueData->Length);
  873. }
  874. else {
  875. status = STATUS_INVALID_PARAMETER_MIX;
  876. }
  877. }
  878. return status;
  879. }
  880. NTSTATUS _GetRegSZValue(
  881. HANDLE KeyHandle,
  882. PWCHAR ValueName,
  883. PUNICODE_STRING ValueData,
  884. PULONG ValueType)
  885. /*++
  886. Reads a REG_SZ string value from the Registry into the supplied
  887. Unicode string. If the Unicode string buffer is not large enough,
  888. it is reallocated.
  889. Arguments:
  890. KeyHandle - Open handle to the parent key of the value to read.
  891. ValueName - The name of the value to read.
  892. ValueData - Destination Unicode string for the value data.
  893. ValueType - On return, contains the Registry type of the value read.
  894. --*/
  895. {
  896. NTSTATUS status;
  897. ULONG resultLength;
  898. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  899. UNICODE_STRING UValueName;
  900. PAGED_CODE();
  901. ValueData->Length = 0;
  902. status = _GetRegStringValue(
  903. KeyHandle,
  904. ValueName,
  905. (PKEY_VALUE_PARTIAL_INFORMATION *) &(ValueData->Buffer),
  906. &(ValueData->MaximumLength));
  907. if (NT_SUCCESS(status)) {
  908. keyValuePartialInformation =
  909. (PKEY_VALUE_PARTIAL_INFORMATION)ValueData->Buffer;
  910. if ((keyValuePartialInformation->Type == REG_SZ) ||
  911. (keyValuePartialInformation->Type == REG_EXPAND_SZ)) {
  912. WCHAR *src;
  913. WCHAR *dst;
  914. ULONG dataLength;
  915. *ValueType = keyValuePartialInformation->Type;
  916. dataLength = keyValuePartialInformation->DataLength;
  917. ASSERT(dataLength <= ValueData->MaximumLength);
  918. dst = ValueData->Buffer;
  919. src = (PWCHAR) &(keyValuePartialInformation->Data);
  920. while (ValueData->Length <= dataLength) {
  921. if ((*dst++ = *src++) == UNICODE_NULL)
  922. break;
  923. ValueData->Length += sizeof(WCHAR);
  924. }
  925. if (ValueData->Length < (ValueData->MaximumLength - 1)) {
  926. ValueData->Buffer[ValueData->Length / sizeof(WCHAR)] =
  927. UNICODE_NULL;
  928. }
  929. }
  930. else {
  931. status = STATUS_INVALID_PARAMETER_MIX;
  932. }
  933. }
  934. return status;
  935. }
  936. PWCHAR _EnumRegMultiSz(
  937. IN PWCHAR MszString,
  938. IN ULONG MszStringLength,
  939. IN ULONG StringIndex)
  940. /*++
  941. Parses a REG_MULTI_SZ string and returns the specified substring.
  942. Arguments:
  943. MszString - A pointer to the REG_MULTI_SZ string.
  944. MszStringLength - The length of the REG_MULTI_SZ string, including the
  945. terminating null character.
  946. StringIndex - Index number of the substring to return. Specifiying
  947. index 0 retrieves the first substring.
  948. Return Value:
  949. A pointer to the specified substring.
  950. Notes:
  951. This code is called at raised IRQL. It is not pageable.
  952. --*/
  953. {
  954. PWCHAR string = MszString;
  955. if (MszStringLength < (2 * sizeof(WCHAR)))
  956. return NULL;
  957. // Find the start of the desired string.
  958. while (StringIndex) {
  959. while (MszStringLength >= sizeof(WCHAR)) {
  960. MszStringLength -= sizeof(WCHAR);
  961. if (*string++ == UNICODE_NULL)
  962. break;
  963. }
  964. // Check for index out of range.
  965. if (MszStringLength < (2 * sizeof(UNICODE_NULL)))
  966. return NULL;
  967. StringIndex--;
  968. }
  969. if (MszStringLength < (2 * sizeof(UNICODE_NULL)))
  970. return NULL;
  971. return string;
  972. }
  973. VOID GetGUID(
  974. OUT PUNICODE_STRING szGuid,
  975. IN int Lana)
  976. /*++
  977. Enumerates through the guid table setup from TSConfig tool
  978. Arguments:
  979. szGuid - This is an out param containing the guid in this format '{ ... }'
  980. Lana - The id to confirm the one to one association
  981. Return Value:
  982. VOID -- _TcpGetTransportAddress will fail if szGuid is invalid
  983. --*/
  984. {
  985. // open guidtable key
  986. HANDLE hKey;
  987. UNICODE_STRING TempString;
  988. OBJECT_ATTRIBUTES ObjectAttributes;
  989. NTSTATUS status;
  990. status = _OpenRegKey(&hKey, REG_GUID_TABLE);
  991. if (NT_SUCCESS(status)) {
  992. // enumerate this key
  993. ULONG ulByteRead = 0;
  994. ULONG Index = 0;
  995. ULONG ulLana = 0;
  996. HANDLE hSubKey;
  997. PKEY_BASIC_INFORMATION pKeyBasicInformation = NULL;
  998. BYTE buffer[ 512 ]; // work space
  999. pKeyBasicInformation = (PKEY_BASIC_INFORMATION)buffer;
  1000. RtlZeroMemory(pKeyBasicInformation, sizeof(buffer));
  1001. do {
  1002. status = ZwEnumerateKey(
  1003. hKey,
  1004. Index,
  1005. KeyBasicInformation,
  1006. (PVOID)pKeyBasicInformation,
  1007. sizeof(buffer),
  1008. &ulByteRead);
  1009. KdPrint(("TDTCP: GetGUID ZwEnumerateKey returned 0x%x\n", status));
  1010. if (status != STATUS_SUCCESS)
  1011. break;
  1012. // extract unicode name
  1013. TempString.Length = (USHORT) pKeyBasicInformation->NameLength;
  1014. TempString.MaximumLength = (USHORT) pKeyBasicInformation->NameLength;
  1015. TempString.Buffer = pKeyBasicInformation->Name;
  1016. RtlZeroMemory( &ObjectAttributes , sizeof( OBJECT_ATTRIBUTES ) );
  1017. InitializeObjectAttributes(
  1018. &ObjectAttributes,
  1019. &TempString,
  1020. OBJ_CASE_INSENSITIVE,
  1021. hKey,
  1022. NULL);
  1023. status = ZwOpenKey(&hSubKey, KEY_READ, &ObjectAttributes);
  1024. if (NT_SUCCESS(status)) {
  1025. status = _GetRegDWORDValue(hSubKey, LANA_ID, &ulLana);
  1026. ZwClose(hSubKey);
  1027. if (NT_SUCCESS(status)) {
  1028. if (Lana == (int)ulLana) {
  1029. KdPrint(("TDTCP:GetGUID We've found a Lana %d\n", ulLana));
  1030. status = MemoryAllocate(TempString.Length +
  1031. sizeof(WCHAR), &szGuid->Buffer);
  1032. if (NT_SUCCESS(status)) {
  1033. szGuid->MaximumLength = TempString.Length +
  1034. sizeof(WCHAR);
  1035. RtlZeroMemory(szGuid->Buffer, szGuid->MaximumLength);
  1036. RtlCopyUnicodeString(szGuid, &TempString);
  1037. break;
  1038. }
  1039. }
  1040. }
  1041. }
  1042. Index++;
  1043. } while (TRUE);
  1044. ZwClose(hKey);
  1045. }
  1046. }