Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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