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.

1249 lines
38 KiB

  1. /****************************************************************************/
  2. // tdpipe.c
  3. //
  4. // TS named pipe transport driver.
  5. //
  6. // Copyright (C) 1998-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <ntosp.h>
  9. #include <winstaw.h>
  10. #define _DEFCHARINFO_
  11. #include <icadd.h>
  12. #include <ctxdd.h>
  13. #include <sdapi.h>
  14. #include <td.h>
  15. #include "tdpipe.h"
  16. #ifdef _HYDRA_
  17. // This becomes the device name
  18. PWCHAR ModuleName = L"tdpipe";
  19. #endif
  20. #ifndef min
  21. #define min(a,b) (((a) < (b)) ? (a) : (b))
  22. #endif
  23. /*=============================================================================
  24. == External Functions Defined
  25. =============================================================================*/
  26. NTSTATUS DeviceOpen( PTD, PSD_OPEN );
  27. NTSTATUS DeviceClose( PTD, PSD_CLOSE );
  28. NTSTATUS DeviceCreateEndpoint( PTD, PICA_STACK_ADDRESS, PICA_STACK_ADDRESS );
  29. NTSTATUS DeviceOpenEndpoint( PTD, PVOID, ULONG );
  30. NTSTATUS DeviceCloseEndpoint( PTD );
  31. NTSTATUS DeviceConnectionWait( PTD, PVOID, ULONG, PULONG );
  32. NTSTATUS DeviceConnectionSend( PTD );
  33. NTSTATUS DeviceConnectionRequest( PTD, PICA_STACK_ADDRESS, PVOID, ULONG, PULONG );
  34. NTSTATUS DeviceIoctl( PTD, PSD_IOCTL );
  35. NTSTATUS DeviceInitializeRead( PTD, PINBUF );
  36. NTSTATUS DeviceSubmitRead( PTD, PINBUF );
  37. NTSTATUS DeviceWaitForRead( PTD );
  38. NTSTATUS DeviceReadComplete( PTD, PUCHAR, PULONG );
  39. NTSTATUS DeviceInitializeWrite( PTD, POUTBUF );
  40. NTSTATUS DeviceWaitForStatus( PTD );
  41. NTSTATUS DeviceCancelIo( PTD );
  42. NTSTATUS DeviceSetParams( PTD );
  43. NTSTATUS DeviceGetLastError( PTD, PICA_STACK_LAST_ERROR );
  44. /*=============================================================================
  45. == Internal Functions Defined
  46. =============================================================================*/
  47. NTSTATUS _TdOpenEndpoint( PTD, PICA_STACK_ADDRESS, PTD_ENDPOINT * );
  48. NTSTATUS _TdCloseEndpoint( PTD, PTD_ENDPOINT );
  49. NTSTATUS _TdStartListen( PTD, PTD_ENDPOINT );
  50. NTSTATUS _TdWaitForListen( PTD, PTD_ENDPOINT );
  51. NTSTATUS _TdConnectRequest( PTD, PTD_ENDPOINT );
  52. /*=============================================================================
  53. == External Functions Referenced
  54. =============================================================================*/
  55. NTSTATUS
  56. ZwClose(
  57. IN HANDLE Handle
  58. );
  59. NTSTATUS
  60. ZwFsControlFile(
  61. IN HANDLE FileHandle,
  62. IN HANDLE Event OPTIONAL,
  63. IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  64. IN PVOID ApcContext OPTIONAL,
  65. OUT PIO_STATUS_BLOCK IoStatusBlock,
  66. IN ULONG IoControlCode,
  67. IN PVOID InputBuffer OPTIONAL,
  68. IN ULONG InputBufferLength,
  69. OUT PVOID OutputBuffer OPTIONAL,
  70. IN ULONG OutputBufferLength
  71. );
  72. NTSTATUS
  73. ZwCreateNamedPipeFile(
  74. OUT PHANDLE FileHandle,
  75. IN ULONG DesiredAccess,
  76. IN POBJECT_ATTRIBUTES ObjectAttributes,
  77. OUT PIO_STATUS_BLOCK IoStatusBlock,
  78. IN ULONG ShareAccess,
  79. IN ULONG CreateDisposition,
  80. IN ULONG CreateOptions,
  81. IN ULONG NamedPipeType,
  82. IN ULONG ReadMode,
  83. IN ULONG CompletionMode,
  84. IN ULONG MaximumInstances,
  85. IN ULONG InboundQuota,
  86. IN ULONG OutboundQuota,
  87. IN PLARGE_INTEGER DefaultTimeout OPTIONAL)
  88. /*++
  89. Creates and opens the server end handle of the first instance of a
  90. specific named pipe or another instance of an existing named pipe.
  91. Arguments:
  92. FileHandle - Supplies a handle to the file on which the service is being
  93. performed.
  94. DesiredAccess - Supplies the types of access that the caller would like to
  95. the file.
  96. ObjectAttributes - Supplies the attributes to be used for file object
  97. (name, SECURITY_DESCRIPTOR, etc.)
  98. IoStatusBlock - Address of the caller's I/O status block.
  99. ShareAccess - Supplies the types of share access that the caller would
  100. like to the file.
  101. CreateDisposition - Supplies the method for handling the create/open.
  102. CreateOptions - Caller options for how to perform the create/open.
  103. NamedPipeType - Type of named pipe to create (Bitstream or message).
  104. ReadMode - Mode in which to read the pipe (Bitstream or message).
  105. CompletionMode - Specifies how the operation is to be completed.
  106. MaximumInstances - Maximum number of simultaneous instances of the named
  107. pipe.
  108. InboundQuota - Specifies the pool quota that is reserved for writes to the
  109. inbound side of the named pipe.
  110. OutboundQuota - Specifies the pool quota that is reserved for writes to
  111. the inbound side of the named pipe.
  112. DefaultTimeout - Optional pointer to a timeout value that is used if a
  113. timeout value is not specified when waiting for an instance of a named
  114. pipe.
  115. Return Value:
  116. The function value is the final status of the create/open operation.
  117. --*/
  118. {
  119. NAMED_PIPE_CREATE_PARAMETERS namedPipeCreateParameters;
  120. NTSTATUS status;
  121. // Check whether or not the DefaultTimeout parameter was specified. If
  122. // so, then capture it in the named pipe create parameter structure.
  123. if (ARGUMENT_PRESENT( DefaultTimeout )) {
  124. // Indicate that a default timeout period was specified.
  125. namedPipeCreateParameters.TimeoutSpecified = TRUE;
  126. namedPipeCreateParameters.DefaultTimeout = *DefaultTimeout;
  127. // A default timeout parameter was specified. Check to see whether
  128. // the caller's mode is kernel and if not capture the parameter inside
  129. // of a try...except clause.
  130. } else {
  131. // Indicate that no default timeout period was specified.
  132. namedPipeCreateParameters.TimeoutSpecified = FALSE;
  133. namedPipeCreateParameters.DefaultTimeout.QuadPart = 0;
  134. }
  135. // Store the remainder of the named pipe-specific parameters in the
  136. // structure for use in the call to the common create file routine.
  137. namedPipeCreateParameters.NamedPipeType = NamedPipeType;
  138. namedPipeCreateParameters.ReadMode = ReadMode;
  139. namedPipeCreateParameters.CompletionMode = CompletionMode;
  140. namedPipeCreateParameters.MaximumInstances = MaximumInstances;
  141. namedPipeCreateParameters.InboundQuota = InboundQuota;
  142. namedPipeCreateParameters.OutboundQuota = OutboundQuota;
  143. status = IoCreateFile( FileHandle,
  144. DesiredAccess,
  145. ObjectAttributes,
  146. IoStatusBlock,
  147. (PLARGE_INTEGER) NULL,
  148. 0L,
  149. ShareAccess,
  150. CreateDisposition,
  151. CreateOptions,
  152. (PVOID) NULL,
  153. 0L,
  154. CreateFileTypeNamedPipe,
  155. &namedPipeCreateParameters,
  156. IO_NO_PARAMETER_CHECKING);
  157. return status;
  158. }
  159. NTSTATUS
  160. ZwCreateFile(
  161. OUT PHANDLE FileHandle,
  162. IN ACCESS_MASK DesiredAccess,
  163. IN POBJECT_ATTRIBUTES ObjectAttributes,
  164. OUT PIO_STATUS_BLOCK IoStatusBlock,
  165. IN PLARGE_INTEGER AllocationSize OPTIONAL,
  166. IN ULONG FileAttributes,
  167. IN ULONG ShareAccess,
  168. IN ULONG CreateDisposition,
  169. IN ULONG CreateOptions,
  170. IN PVOID EaBuffer OPTIONAL,
  171. IN ULONG EaLength
  172. );
  173. extern POBJECT_TYPE *IoFileObjectType;
  174. extern PDEVICE_OBJECT DrvDeviceObject;
  175. /*******************************************************************************
  176. * DeviceOpen
  177. *
  178. * Allocate and initialize private data structures
  179. *
  180. * pTd (input)
  181. * Pointer to TD data structure
  182. * pSdOpen (input/output)
  183. * Points to the parameter structure SD_OPEN.
  184. ******************************************************************************/
  185. NTSTATUS DeviceOpen(PTD pTd, PSD_OPEN pSdOpen)
  186. {
  187. PTDPIPE pTdPipe;
  188. NTSTATUS Status;
  189. /*
  190. * Hideous HACK alert! NULL out the unload routine for TDPIPE since
  191. * the timing is hosed and we sometimes unload before the IO completion
  192. * routine has issued a return statement. BARF!
  193. */
  194. // see correction of the hack below...
  195. //DrvDeviceObject->DriverObject->DriverUnload = NULL;
  196. // correction of the above hack: a pointer to the device object of the current
  197. // driver is stored in the TD struct. When an IRP is initialized, the function
  198. // IoSetCompletionRoutineEx will be used and this function will set a parent
  199. // completion routine which references and dereferences the device object
  200. // around the call of the normal completion routine in order to maintain the
  201. // driver in memory.
  202. // DO NOT USE THIS POINTER AFTER THE DeviceClose !!!
  203. pTd->pSelfDeviceObject = pSdOpen->DeviceObject;
  204. /*
  205. * Set protocol driver class
  206. */
  207. pTd->SdClass = SdNetwork; // until we have SdPipe defined
  208. /*
  209. * Return size of header and trailer
  210. */
  211. pSdOpen->SdOutBufHeader = 0;
  212. pSdOpen->SdOutBufTrailer = 0;
  213. /*
  214. * Allocate PIPE TD data structure
  215. */
  216. pTdPipe = IcaStackAllocatePoolWithTag(NonPagedPool, sizeof(*pTdPipe), 'ipDT');
  217. if (pTdPipe != NULL) {
  218. /*
  219. * Initialize TDPIPE data structure
  220. */
  221. RtlZeroMemory(pTdPipe, sizeof(*pTdPipe));
  222. pTd->pPrivate = pTdPipe;
  223. Status = STATUS_SUCCESS;
  224. }
  225. else {
  226. Status = STATUS_NO_MEMORY;
  227. }
  228. return Status;
  229. }
  230. /*******************************************************************************
  231. * DeviceClose
  232. *
  233. * Close transport driver
  234. *
  235. * NOTE: this must not close the current connection endpoint
  236. ******************************************************************************/
  237. NTSTATUS DeviceClose(PTD pTd, PSD_CLOSE pSdClose)
  238. {
  239. PTDPIPE pTdPipe;
  240. PTD_ENDPOINT pEndpoint;
  241. pTd->pSelfDeviceObject = NULL;
  242. pTdPipe = (PTDPIPE) pTd->pPrivate;
  243. /*
  244. * Close address endpoint if we have one
  245. */
  246. if (pEndpoint = pTdPipe->pAddressEndpoint) {
  247. pTdPipe->pAddressEndpoint = NULL;
  248. _TdCloseEndpoint(pTd, pEndpoint);
  249. }
  250. return STATUS_SUCCESS;
  251. }
  252. /*******************************************************************************
  253. * DeviceCreateEndpoint
  254. *
  255. * Create a new endpoint
  256. *
  257. * pTd (input)
  258. * Pointer to TD data structure
  259. * pLocalAddress (input)
  260. * Pointer to local address (or null)
  261. * pReturnedAddress (input)
  262. * Pointer to location to save returned (created) address (or null)
  263. ******************************************************************************/
  264. NTSTATUS DeviceCreateEndpoint(
  265. PTD pTd,
  266. PICA_STACK_ADDRESS pLocalAddress,
  267. PICA_STACK_ADDRESS pReturnedAddress)
  268. {
  269. PTDPIPE pTdPipe;
  270. PTD_ENDPOINT pEndpoint;
  271. NTSTATUS Status;
  272. pTdPipe = (PTDPIPE) pTd->pPrivate;
  273. /*
  274. * Create an endpoint which ConnectionWait will use to listen on.
  275. */
  276. Status = _TdOpenEndpoint(pTd, pLocalAddress, &pEndpoint);
  277. if (NT_SUCCESS(Status)) {
  278. /*
  279. * Prepare to listen on the new address endpoint.
  280. */
  281. Status = _TdStartListen(pTd, pEndpoint);
  282. if (NT_SUCCESS(Status)) {
  283. /*
  284. * Save a pointer to the address endpoint
  285. */
  286. pTdPipe->pAddressEndpoint = pEndpoint;
  287. Status = STATUS_SUCCESS;
  288. }
  289. else {
  290. _TdCloseEndpoint(pTd, pEndpoint);
  291. }
  292. }
  293. return Status;
  294. }
  295. /*******************************************************************************
  296. * DeviceOpenEndpoint
  297. *
  298. * Open an existing endpoint
  299. *
  300. * pTd (input)
  301. * Pointer to TD data structure
  302. * pIcaEndpoint (input)
  303. * Pointer to ICA endpoint structure
  304. * IcaEndpointLength (input)
  305. * length of endpoint data
  306. ******************************************************************************/
  307. NTSTATUS DeviceOpenEndpoint(
  308. PTD pTd,
  309. PVOID pIcaEndpoint,
  310. ULONG IcaEndpointLength)
  311. {
  312. PTDPIPE pTdPipe;
  313. PTD_STACK_ENDPOINT pStackEndpoint;
  314. NTSTATUS Status;
  315. pTdPipe = (PTDPIPE) pTd->pPrivate;
  316. TRACE((pTd->pContext, TC_TD, TT_API2,
  317. "TDPIPE: DeviceOpenEndpoint, copying existing endpoint\n"));
  318. try {
  319. /*
  320. * Verify the stack endpoint data looks valid
  321. */
  322. pStackEndpoint = (PTD_STACK_ENDPOINT) pIcaEndpoint;
  323. if (IcaEndpointLength == sizeof(TD_STACK_ENDPOINT) &&
  324. //pStackEndpoint->pEndpoint >= MM_LOWEST_NONPAGED_SYSTEM_START &&
  325. //pStackEndpoint->pEndpoint <= MM_NONPAGED_POOL_END &&
  326. MmIsNonPagedSystemAddressValid(pStackEndpoint->pEndpoint)) {
  327. /*
  328. * Save endpoint as the current connection endpoint
  329. */
  330. pTdPipe->pConnectionEndpoint = pStackEndpoint->pEndpoint;
  331. /*
  332. * Save the file/device objects used for I/O in the TD structure
  333. */
  334. pTd->pFileObject = pTdPipe->pConnectionEndpoint->pFileObject;
  335. pTd->pDeviceObject = pTdPipe->pConnectionEndpoint->pDeviceObject;
  336. Status = STATUS_SUCCESS;
  337. }
  338. else {
  339. Status = STATUS_INVALID_PARAMETER;
  340. }
  341. } except (EXCEPTION_EXECUTE_HANDLER) {
  342. Status = GetExceptionCode();
  343. }
  344. return Status;
  345. }
  346. /*******************************************************************************
  347. * DeviceCloseEndpoint
  348. ******************************************************************************/
  349. NTSTATUS DeviceCloseEndpoint(PTD pTd)
  350. {
  351. PTDPIPE pTdPipe;
  352. PTD_ENDPOINT pEndpoint;
  353. NTSTATUS Status;
  354. pTdPipe = (PTDPIPE) pTd->pPrivate;
  355. /*
  356. * Close connection endpoint if we have one
  357. * NOTE: The address endpoint, if there is one,
  358. * gets closed in the DeviceClose routine.
  359. */
  360. if (pEndpoint = pTdPipe->pConnectionEndpoint) {
  361. pTd->pFileObject = NULL;
  362. pTd->pDeviceObject = NULL;
  363. pTdPipe->pConnectionEndpoint = NULL;
  364. _TdCloseEndpoint(pTd, pEndpoint);
  365. }
  366. return STATUS_SUCCESS;
  367. }
  368. /*******************************************************************************
  369. * DeviceConnectionWait
  370. *
  371. * NOTE: The endpoint structure is an opaque, variable length data
  372. * structure whose length and contents are determined by the
  373. * transport driver.
  374. *
  375. * ENTRY:
  376. * pTd (input)
  377. * Pointer to TD data structure
  378. * pIcaEndpoint (output)
  379. * Points to a buffer to receive the current endpoint
  380. * Length (input)
  381. * Length of the buffer pointed to by pIcaEndpoint
  382. * BytesReturned (output)
  383. * Points to the actual number of bytes written to pIcaEndpoint
  384. *
  385. * EXIT:
  386. * STATUS_SUCCESS - no error
  387. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  388. ******************************************************************************/
  389. NTSTATUS DeviceConnectionWait(
  390. PTD pTd,
  391. PVOID pIcaEndpoint,
  392. ULONG Length,
  393. PULONG BytesReturned)
  394. {
  395. PTDPIPE pTdPipe;
  396. PTD_STACK_ENDPOINT pStackEndpoint;
  397. NTSTATUS Status;
  398. pTdPipe = (PTDPIPE) pTd->pPrivate;
  399. /*
  400. * Initialize return buffer size
  401. */
  402. *BytesReturned = sizeof(TD_STACK_ENDPOINT);
  403. /*
  404. * Verify output endpoint buffer is large enough
  405. */
  406. if (Length >= sizeof(TD_STACK_ENDPOINT)) {
  407. /*
  408. * Ensure we have an address endpoint already
  409. */
  410. if (pTdPipe->pAddressEndpoint != NULL) {
  411. /*
  412. * Wait for a new virtual circuit connection.
  413. */
  414. Status = _TdWaitForListen(pTd, pTdPipe->pAddressEndpoint);
  415. if (NT_SUCCESS(Status)) {
  416. /*
  417. * The listen was successful.
  418. * Return the existing address endpoint as the connection endpoint
  419. * and forget that we have an address endpoint anymore.
  420. */
  421. pStackEndpoint = (PTD_STACK_ENDPOINT) pIcaEndpoint;
  422. pStackEndpoint->pEndpoint = pTdPipe->pAddressEndpoint;
  423. pTdPipe->pAddressEndpoint = NULL;
  424. }
  425. else {
  426. goto done;
  427. }
  428. }
  429. else {
  430. Status = STATUS_DEVICE_NOT_READY;
  431. goto done;
  432. }
  433. }
  434. else {
  435. Status = STATUS_BUFFER_TOO_SMALL;
  436. goto done;
  437. }
  438. done:
  439. return Status;
  440. }
  441. /*******************************************************************************
  442. * DeviceConnectionSend
  443. *
  444. * Initialize host module data structure
  445. * -- this structure gets sent to the client
  446. ******************************************************************************/
  447. NTSTATUS DeviceConnectionSend(PTD pTd)
  448. {
  449. return STATUS_NOT_SUPPORTED;
  450. }
  451. /*******************************************************************************
  452. * DeviceConnectionRequest
  453. *
  454. * Initiate a connection to the specified remote address
  455. *
  456. * ENTRY:
  457. * pTd (input)
  458. * Pointer to TD data structure
  459. * pRemoteAddress (input)
  460. * Pointer to remote address to connect to
  461. * pIcaEndpoint (output)
  462. * Points to a buffer to receive the current endpoint
  463. * Length (input)
  464. * Length of the buffer pointed to by pIcaEndpoint
  465. * BytesReturned (output)
  466. * Pointer to location to return length of pIcaEndpoint
  467. *
  468. * EXIT:
  469. * STATUS_SUCCESS - no error
  470. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  471. ******************************************************************************/
  472. NTSTATUS DeviceConnectionRequest(
  473. PTD pTd,
  474. PICA_STACK_ADDRESS pRemoteAddress,
  475. PVOID pIcaEndpoint,
  476. ULONG Length,
  477. PULONG BytesReturned)
  478. {
  479. PTDPIPE pTdPipe;
  480. PTD_ENDPOINT pConnectionEndpoint;
  481. PTD_STACK_ENDPOINT pStackEndpoint;
  482. NTSTATUS Status;
  483. ASSERT( pRemoteAddress );
  484. if (pRemoteAddress != NULL) {
  485. /*
  486. * Initialize return buffer size
  487. */
  488. *BytesReturned = sizeof(TD_STACK_ENDPOINT);
  489. /*
  490. * Verify output endpoint buffer is large enough
  491. */
  492. if (Length >= sizeof(TD_STACK_ENDPOINT)) {
  493. pTdPipe = (PTDPIPE) pTd->pPrivate;
  494. /*
  495. * Create an endpoint which we will use to connect with
  496. */
  497. Status = _TdOpenEndpoint(pTd, pRemoteAddress, &pConnectionEndpoint);
  498. if (NT_SUCCESS(Status)) {
  499. /*
  500. * Attempt to connect to the specified remote address
  501. */
  502. Status = _TdConnectRequest(pTd, pConnectionEndpoint);
  503. if (NT_SUCCESS(Status)) {
  504. /*
  505. * Fill in the stack endpoint structure to be returned
  506. */
  507. pStackEndpoint = (PTD_STACK_ENDPOINT) pIcaEndpoint;
  508. pStackEndpoint->pEndpoint = pConnectionEndpoint;
  509. /*
  510. * Save a pointer to the connection endpoint
  511. */
  512. pTdPipe->pConnectionEndpoint = pConnectionEndpoint;
  513. /*
  514. * Save the file/device objects for I/O in the TD structure
  515. */
  516. pTd->pFileObject = pConnectionEndpoint->pFileObject;
  517. pTd->pDeviceObject = pConnectionEndpoint->pDeviceObject;
  518. return STATUS_SUCCESS;
  519. }
  520. else {
  521. goto badconnect;
  522. }
  523. }
  524. else {
  525. goto badcreate;
  526. }
  527. }
  528. else {
  529. Status = STATUS_BUFFER_TOO_SMALL;
  530. goto buftoosmall;
  531. }
  532. }
  533. else {
  534. return STATUS_INVALID_PARAMETER;
  535. }
  536. /*=============================================================================
  537. == Error returns
  538. =============================================================================*/
  539. badconnect:
  540. _TdCloseEndpoint(pTd, pConnectionEndpoint);
  541. badcreate:
  542. buftoosmall:
  543. return Status;
  544. }
  545. /*******************************************************************************
  546. * DeviceIoctl
  547. *
  548. * Query/Set configuration information for the td.
  549. *
  550. * pTd (input)
  551. * Pointer to TD data structure
  552. * pSdIoctl (input/output)
  553. * Points to the parameter structure SD_IOCTL
  554. ******************************************************************************/
  555. NTSTATUS DeviceIoctl(PTD pTd, PSD_IOCTL pSdIoctl)
  556. {
  557. return STATUS_NOT_SUPPORTED;
  558. }
  559. /*******************************************************************************
  560. * DeviceInitializeRead
  561. ******************************************************************************/
  562. NTSTATUS DeviceInitializeRead(PTD pTd, PINBUF pInBuf)
  563. {
  564. PIRP irp;
  565. PIO_STACK_LOCATION irpSp;
  566. irp = pInBuf->pIrp;
  567. irpSp = IoGetNextIrpStackLocation(irp);
  568. /*
  569. * Set the major function code and read parameters.
  570. */
  571. irpSp->MajorFunction = IRP_MJ_READ;
  572. irpSp->Parameters.Read.Length = pTd->InBufHeader + pTd->OutBufLength;
  573. ASSERT(irp->MdlAddress == NULL);
  574. /*
  575. * Determine whether the target device performs direct or buffered I/O.
  576. */
  577. if (pTd->pDeviceObject->Flags & DO_BUFFERED_IO) {
  578. /*
  579. * The target device supports buffered I/O operations. Since our
  580. * input buffer is allocated from NonPagedPool memory, we can just
  581. * point the SystemBuffer to our input buffer. No buffer copying
  582. * will be required.
  583. */
  584. irp->AssociatedIrp.SystemBuffer = pInBuf->pBuffer;
  585. irp->UserBuffer = pInBuf->pBuffer;
  586. irp->Flags |= IRP_BUFFERED_IO;
  587. } else if ( pTd->pDeviceObject->Flags & DO_DIRECT_IO ) {
  588. /*
  589. * The target device supports direct I/O operations.
  590. * A MDL is preallocated in the PTD and never freed by the
  591. * Device level TD. So just initialize it here.
  592. */
  593. MmInitializeMdl( pInBuf->pMdl, pInBuf->pBuffer, pTd->InBufHeader+pTd->OutBufLength );
  594. MmBuildMdlForNonPagedPool( pInBuf->pMdl );
  595. irp->MdlAddress = pInBuf->pMdl;
  596. } else {
  597. /*
  598. * The operation is neither buffered nor direct. Simply pass the
  599. * address of the buffer in the packet to the driver.
  600. */
  601. irp->UserBuffer = pInBuf->pBuffer;
  602. }
  603. return STATUS_SUCCESS;
  604. }
  605. /*******************************************************************************
  606. * DeviceSubmitRead
  607. *
  608. * Submit the read IRP to the driver.
  609. ******************************************************************************/
  610. NTSTATUS DeviceSubmitRead(PTD pTd, PINBUF pInBuf)
  611. {
  612. return IoCallDriver(pTd->pDeviceObject, pInBuf->pIrp);
  613. }
  614. /*******************************************************************************
  615. * DeviceWaitForRead
  616. ******************************************************************************/
  617. NTSTATUS DeviceWaitForRead(PTD pTd)
  618. {
  619. /*
  620. * Just wait on the input event and return the wait status
  621. */
  622. return IcaWaitForSingleObject(pTd->pContext, &pTd->InputEvent, -1);
  623. }
  624. /*******************************************************************************
  625. * DeviceReadComplete
  626. *
  627. * pTd (input)
  628. * Pointer to TD data structure
  629. * pBuffer (input)
  630. * Pointer to input buffer
  631. * pByteCount (input/output)
  632. * Pointer to location to return byte count read
  633. ******************************************************************************/
  634. NTSTATUS DeviceReadComplete(PTD pTd, PUCHAR pBuffer, PULONG pByteCount)
  635. {
  636. return STATUS_SUCCESS;
  637. }
  638. /*******************************************************************************
  639. * DeviceInitializeWrite
  640. ******************************************************************************/
  641. NTSTATUS DeviceInitializeWrite(PTD pTd, POUTBUF pOutBuf)
  642. {
  643. PIRP Irp;
  644. PIO_STACK_LOCATION _IRPSP;
  645. TRACE(( pTd->pContext, TC_TD, TT_API1,
  646. "TDPIPE: DeviceInitializeWrite Entry\n" ));
  647. Irp = pOutBuf->pIrp;
  648. _IRPSP = IoGetNextIrpStackLocation(Irp);
  649. /*
  650. * Setup a WRITE IRP
  651. */
  652. _IRPSP->MajorFunction = IRP_MJ_WRITE;
  653. _IRPSP->Parameters.Write.Length = pOutBuf->ByteCount;
  654. ASSERT(Irp->MdlAddress == NULL);
  655. /*
  656. * Determine whether the target device performs direct or buffered I/O.
  657. */
  658. if (pTd->pDeviceObject->Flags & DO_BUFFERED_IO) {
  659. /*
  660. * The target device supports buffered I/O operations. Since our
  661. * output buffer is allocated from NonPagedPool memory, we can just
  662. * point the SystemBuffer to the output buffer. No buffer copying
  663. * will be required.
  664. */
  665. Irp->AssociatedIrp.SystemBuffer = pOutBuf->pBuffer;
  666. Irp->UserBuffer = pOutBuf->pBuffer;
  667. Irp->Flags |= IRP_BUFFERED_IO;
  668. } else if ( pTd->pDeviceObject->Flags & DO_DIRECT_IO ) {
  669. /*
  670. * The target device supports direct I/O operations.
  671. * Initialize the MDL and point to it from the IRP.
  672. *
  673. * This MDL is allocated for every OUTBUF, and free'd with it.
  674. */
  675. MmInitializeMdl( pOutBuf->pMdl, pOutBuf->pBuffer, pOutBuf->ByteCount );
  676. MmBuildMdlForNonPagedPool( pOutBuf->pMdl );
  677. Irp->MdlAddress = pOutBuf->pMdl;
  678. } else {
  679. /*
  680. * The operation is neither buffered nor direct. Simply pass the
  681. * address of the buffer in the packet to the driver.
  682. */
  683. Irp->UserBuffer = pOutBuf->pBuffer;
  684. }
  685. return STATUS_SUCCESS;
  686. }
  687. /*******************************************************************************
  688. * DeviceWaitForStatus
  689. *
  690. * Wait for device status to change (unused for network TDs)
  691. ******************************************************************************/
  692. NTSTATUS DeviceWaitForStatus(PTD pTd)
  693. {
  694. return STATUS_INVALID_DEVICE_REQUEST;
  695. }
  696. /*******************************************************************************
  697. * DeviceCancelIo
  698. *
  699. * cancel all current and future i/o
  700. ******************************************************************************/
  701. NTSTATUS DeviceCancelIo(PTD pTd)
  702. {
  703. return STATUS_SUCCESS;
  704. }
  705. /*******************************************************************************
  706. * DeviceQueryRemoteAddress
  707. *
  708. * not supported for Pipe transport
  709. ******************************************************************************/
  710. NTSTATUS
  711. DeviceQueryRemoteAddress(
  712. PTD pTd,
  713. PVOID pIcaEndpoint,
  714. ULONG EndpointSize,
  715. PVOID pOutputAddress,
  716. ULONG OutputAddressSize,
  717. PULONG BytesReturned)
  718. {
  719. //
  720. // unsupported for Async
  721. //
  722. return STATUS_NOT_SUPPORTED;
  723. }
  724. /*******************************************************************************
  725. * DeviceSetParams
  726. *
  727. * Set device pararameters (unused for network TDs)
  728. ******************************************************************************/
  729. NTSTATUS DeviceSetParams(PTD pTd)
  730. {
  731. return STATUS_SUCCESS;
  732. }
  733. /*******************************************************************************
  734. * DeviceGetLastError
  735. *
  736. * This routine returns the last transport error code and message
  737. *
  738. * ENTRY:
  739. * pTd (input)
  740. * Pointer to TD data structure
  741. * pLastError (output)
  742. * address to return information on last transport error
  743. ******************************************************************************/
  744. NTSTATUS DeviceGetLastError(PTD pTd, PICA_STACK_LAST_ERROR pLastError)
  745. {
  746. return STATUS_SUCCESS;
  747. }
  748. /*******************************************************************************
  749. * _TdOpenEndpoint
  750. *
  751. * Open a new endpoint object
  752. *
  753. * ENTRY:
  754. * pTd (input)
  755. * Pointer to TD data structure
  756. * pPipeName (input)
  757. * Pointer to ICA_STACK_ADDRESS containing pipe name
  758. * ppEndpoint (output)
  759. * Pointer to location to return TD_ENDPOINT pointer
  760. ******************************************************************************/
  761. NTSTATUS _TdOpenEndpoint(
  762. IN PTD pTd,
  763. IN PICA_STACK_ADDRESS pPipeName,
  764. OUT PTD_ENDPOINT *ppEndpoint)
  765. {
  766. ULONG Length;
  767. PTD_ENDPOINT pEndpoint;
  768. NTSTATUS Status;
  769. /*
  770. * Allocate an endpoint object and room for the pipe name
  771. */
  772. if (pPipeName == NULL) {
  773. return STATUS_INVALID_PARAMETER;
  774. }
  775. Length = wcslen( (PWSTR)pPipeName ) * sizeof( WCHAR );
  776. pEndpoint = IcaStackAllocatePoolWithTag(
  777. NonPagedPool,
  778. sizeof(*pEndpoint) + Length + sizeof(UNICODE_NULL),
  779. 'ipDT' );
  780. if (pEndpoint != NULL) {
  781. RtlZeroMemory(pEndpoint, sizeof(*pEndpoint));
  782. Status = IcaCreateHandle( (PVOID)pEndpoint, sizeof(*pEndpoint) + Length + sizeof(UNICODE_NULL), &pEndpoint->hConnectionEndPointIcaHandle );
  783. if (!NT_SUCCESS(Status)) {
  784. IcaStackFreePool(pEndpoint);
  785. return Status;
  786. }
  787. /*
  788. * Build the pipe name UNICODE_STRING and copy it
  789. */
  790. pEndpoint->PipeName.Length = (USHORT)Length;
  791. pEndpoint->PipeName.MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
  792. pEndpoint->PipeName.Buffer = (PWCHAR)(pEndpoint + 1);
  793. RtlCopyMemory( pEndpoint->PipeName.Buffer, pPipeName, Length );
  794. *ppEndpoint = pEndpoint;
  795. Status = STATUS_SUCCESS;
  796. }
  797. else {
  798. Status = STATUS_NO_MEMORY;
  799. }
  800. return Status;
  801. }
  802. /*******************************************************************************
  803. * _TdCloseEndpoint
  804. *
  805. * Close an endpoint object
  806. *
  807. * pTd (input)
  808. * Pointer to TD data structure
  809. * pEndpoint (input)
  810. * Pointer TD_ENDPOINT object
  811. ******************************************************************************/
  812. NTSTATUS _TdCloseEndpoint(IN PTD pTd, IN PTD_ENDPOINT pEndpoint)
  813. {
  814. IO_STATUS_BLOCK IoStatus;
  815. NTSTATUS Status;
  816. NTSTATUS Status2;
  817. PVOID pContext;
  818. ULONG ContextLength;
  819. /*
  820. * If we have a file object, then dereference it and
  821. * close the corresponding file handle.
  822. */
  823. if ( pEndpoint->pFileObject ) {
  824. ASSERT( pEndpoint->pDeviceObject );
  825. /* This ZwFsControlFile and following lines were taken out because
  826. in npfs.sys the FSCTL_PIPE_DISCONNECT causes data in the pipe's internal
  827. buffers to be thrown out. This means if the shadower end of the pipe (the
  828. passthru stack) has sent out a partial packet to his client, he will never
  829. get the rest of it, which is BAD!
  830. */
  831. #ifdef notdef
  832. Status = ZwFsControlFile(
  833. pEndpoint->PipeHandle,
  834. NULL,
  835. NULL,
  836. NULL,
  837. &IoStatus,
  838. FSCTL_PIPE_DISCONNECT,
  839. NULL,
  840. 0,
  841. NULL,
  842. 0 );
  843. if ( Status == STATUS_PENDING ) {
  844. Status = IcaWaitForSingleObject( pTd->pContext,
  845. &pEndpoint->pFileObject->Event,
  846. -1 );
  847. if ( NT_SUCCESS( Status ) ) {
  848. Status = IoStatus.Status;
  849. }
  850. }
  851. /*
  852. * Status should be either SUCCESS,
  853. * PIPE_DISCONNECTED if the server end is already disconnected,
  854. * or ILLEGAL_FUNCTION if this is the client end of the pipe.
  855. */
  856. ASSERT( Status == STATUS_SUCCESS ||
  857. Status == STATUS_PIPE_DISCONNECTED ||
  858. Status == STATUS_ILLEGAL_FUNCTION ||
  859. Status == STATUS_CTX_CLOSE_PENDING );
  860. #endif
  861. ObDereferenceObject( pEndpoint->pFileObject );
  862. pEndpoint->pFileObject = NULL;
  863. pEndpoint->pDeviceObject = NULL;
  864. ASSERT( pEndpoint->PipeHandle );
  865. ASSERT( pEndpoint->PipeHandleProcess == IoGetCurrentProcess() );
  866. ZwClose( pEndpoint->PipeHandle );
  867. pEndpoint->PipeHandle = NULL;
  868. pEndpoint->PipeHandleProcess = NULL;
  869. }
  870. /*
  871. * If the Enpoint has a handle, close it.
  872. */
  873. if (pEndpoint->hConnectionEndPointIcaHandle != NULL) {
  874. Status2 = IcaCloseHandle( pEndpoint->hConnectionEndPointIcaHandle , &pContext, &ContextLength );
  875. }
  876. /*
  877. * Free the endpoint object (this also free's the pipe name string)
  878. */
  879. IcaStackFreePool(pEndpoint);
  880. return STATUS_SUCCESS;
  881. }
  882. /*******************************************************************************
  883. * _TdStartListen
  884. *
  885. * Initialize an endpoint for listening
  886. *
  887. * pTd (input)
  888. * Pointer to TD data structure
  889. * pEndpoint (input)
  890. * Pointer TD_ENDPOINT object
  891. ******************************************************************************/
  892. NTSTATUS _TdStartListen(IN PTD pTd, IN PTD_ENDPOINT pEndpoint)
  893. {
  894. OBJECT_ATTRIBUTES Obja;
  895. LARGE_INTEGER Timeout;
  896. IO_STATUS_BLOCK IoStatus;
  897. HANDLE pipeHandle;
  898. PFILE_OBJECT pipeFileObject;
  899. NTSTATUS Status;
  900. InitializeObjectAttributes(
  901. &Obja,
  902. &pEndpoint->PipeName,
  903. OBJ_CASE_INSENSITIVE,
  904. NULL,
  905. NULL);
  906. Timeout.QuadPart = -10 * 1000 * 5000; // 5 seconds
  907. /*
  908. * Create the server side of the pipe
  909. */
  910. Status = ZwCreateNamedPipeFile(
  911. &pipeHandle,
  912. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  913. &Obja,
  914. &IoStatus,
  915. FILE_SHARE_READ | FILE_SHARE_WRITE,
  916. FILE_CREATE,
  917. 0,
  918. FILE_PIPE_MESSAGE_TYPE,
  919. FILE_PIPE_MESSAGE_MODE,
  920. FILE_PIPE_QUEUE_OPERATION,
  921. 1,
  922. 1024, /* inbound */
  923. 1024 * 20, /* outbound */
  924. &Timeout);
  925. if (NT_SUCCESS(Status)) {
  926. /*
  927. * Get a pointer reference to the pipe object
  928. */
  929. Status = ObReferenceObjectByHandle(
  930. pipeHandle,
  931. 0L, // DesiredAccess
  932. NULL,
  933. KernelMode,
  934. (PVOID *)&pipeFileObject,
  935. NULL);
  936. ASSERT(NT_SUCCESS(Status));
  937. /*
  938. * Initialize the endpoint object and return a pointer to it
  939. */
  940. pEndpoint->PipeHandle = pipeHandle;
  941. pEndpoint->PipeHandleProcess = IoGetCurrentProcess();
  942. pEndpoint->pFileObject = pipeFileObject;
  943. pEndpoint->pDeviceObject = IoGetRelatedDeviceObject(pipeFileObject);
  944. Status = STATUS_SUCCESS;
  945. }
  946. else {
  947. TRACE((pTd->pContext, TC_TD, TT_ERROR,
  948. "TDPIPE: _TdStartListen failed (lx)\n", Status));
  949. }
  950. return Status;
  951. }
  952. /*******************************************************************************
  953. * _TdWaitForListen
  954. *
  955. * For for an incoming connection request and accept it
  956. *
  957. * pTd (input)
  958. * Pointer to TD data structure
  959. * pEndpoint (input)
  960. * Pointer to Address endpoint object
  961. ******************************************************************************/
  962. NTSTATUS _TdWaitForListen(IN PTD pTd, IN PTD_ENDPOINT pEndpoint)
  963. {
  964. PTDPIPE pTdPipe;
  965. PFILE_OBJECT pFileObject;
  966. NTSTATUS Status;
  967. /*
  968. * Get pointer to PIPE parameters
  969. */
  970. pTdPipe = (PTDPIPE) pTd->pPrivate;
  971. /*
  972. * Wait for a connection attempt to arrive.
  973. */
  974. Status = ZwFsControlFile(
  975. pEndpoint->PipeHandle,
  976. NULL,
  977. NULL,
  978. NULL,
  979. &pTdPipe->IoStatus,
  980. FSCTL_PIPE_LISTEN,
  981. NULL,
  982. 0,
  983. NULL,
  984. 0);
  985. if (Status == STATUS_PENDING) {
  986. /*
  987. * Increment the pointer reference count so the file
  988. * doesn't go away while we're waiting below.
  989. */
  990. pFileObject = pEndpoint->pFileObject;
  991. Status = ObReferenceObjectByPointer( pEndpoint->pFileObject,
  992. SYNCHRONIZE,
  993. *IoFileObjectType,
  994. KernelMode );
  995. ASSERT( Status == STATUS_SUCCESS );
  996. Status = IcaWaitForSingleObject( pTd->pContext,
  997. &pFileObject->Event,
  998. 10000 );
  999. ObDereferenceObject( pFileObject );
  1000. if ( Status == STATUS_TIMEOUT ) {
  1001. ZwFsControlFile( pEndpoint->PipeHandle,
  1002. NULL,
  1003. NULL,
  1004. NULL,
  1005. &pTdPipe->IoStatus,
  1006. FSCTL_PIPE_DISCONNECT,
  1007. NULL,
  1008. 0,
  1009. NULL,
  1010. 0 );
  1011. Status = STATUS_IO_TIMEOUT;
  1012. } else if ( NT_SUCCESS( Status ) ) {
  1013. Status = pTdPipe->IoStatus.Status;
  1014. }
  1015. }
  1016. // Let pipe connected go thru since it means the client beat us to the pipe
  1017. else {
  1018. if (!NT_SUCCESS( Status ) && (Status != STATUS_PIPE_CONNECTED))
  1019. goto badlisten;
  1020. }
  1021. return STATUS_SUCCESS;
  1022. /*=============================================================================
  1023. == Error returns
  1024. =============================================================================*/
  1025. badlisten:
  1026. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1027. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  1028. "TDPIPE: _TdWaitForListen failed(lx)\n", Status));
  1029. }
  1030. return Status;
  1031. }
  1032. /*******************************************************************************
  1033. * _TdConnectRequest
  1034. *
  1035. * Attempt to connect to a remote address
  1036. ******************************************************************************/
  1037. NTSTATUS _TdConnectRequest(IN PTD pTd, IN PTD_ENDPOINT pEndpoint)
  1038. {
  1039. OBJECT_ATTRIBUTES Obja;
  1040. IO_STATUS_BLOCK IoStatus;
  1041. HANDLE pipeHandle;
  1042. PFILE_OBJECT pipeFileObject;
  1043. NTSTATUS Status;
  1044. InitializeObjectAttributes(
  1045. &Obja,
  1046. &pEndpoint->PipeName,
  1047. OBJ_CASE_INSENSITIVE,
  1048. NULL,
  1049. NULL);
  1050. /*
  1051. * Open the client end of the pipe
  1052. */
  1053. Status = ZwCreateFile(
  1054. &pipeHandle,
  1055. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1056. &Obja,
  1057. &IoStatus,
  1058. NULL,
  1059. FILE_ATTRIBUTE_NORMAL,
  1060. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1061. FILE_OPEN,
  1062. FILE_NON_DIRECTORY_FILE,
  1063. NULL,
  1064. 0 );
  1065. if (NT_SUCCESS(Status)) {
  1066. /*
  1067. * Get a pointer reference to the pipe object
  1068. */
  1069. Status = ObReferenceObjectByHandle(
  1070. pipeHandle,
  1071. 0L, // DesiredAccess
  1072. NULL,
  1073. KernelMode,
  1074. (PVOID *)&pipeFileObject,
  1075. NULL);
  1076. ASSERT(NT_SUCCESS(Status));
  1077. /*
  1078. * Initialize the endpoint object and return a pointer to it
  1079. */
  1080. pEndpoint->PipeHandle = pipeHandle;
  1081. pEndpoint->PipeHandleProcess = IoGetCurrentProcess();
  1082. pEndpoint->pFileObject = pipeFileObject;
  1083. pEndpoint->pDeviceObject = IoGetRelatedDeviceObject( pipeFileObject );
  1084. Status = STATUS_SUCCESS;
  1085. }
  1086. else {
  1087. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1088. TRACE((pTd->pContext, TC_TD, TT_ERROR,
  1089. "TDPIPE: _TdConnectRequest failed (lx)\n", Status));
  1090. }
  1091. }
  1092. return Status;
  1093. }