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.

2139 lines
65 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. rxtdi.c
  5. Abstract:
  6. This module implements the NT TDI related routines used by RXCE. The wrappers are necessary to
  7. ensure that all the OS dependencies can be localized to select modules like this for
  8. customization.
  9. Revision History:
  10. Balan Sethu Raman [SethuR] 15-Feb-1995
  11. Notes:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "tdikrnl.h"
  16. #include "rxtdip.h"
  17. //
  18. // The debug trace level
  19. //
  20. #define Dbg (DEBUG_TRACE_RXCETDI)
  21. LARGE_INTEGER ConnectionTimeOut = {0,0};
  22. #define CANCELLED_CONNECT_IRP IntToPtr(0xffffffff)
  23. #if DBG
  24. void
  25. DbgDumpTransportAddress(
  26. PWSTR RoutineName,
  27. PRXCE_TRANSPORT pTransport,
  28. PTRANSPORT_ADDRESS pTA
  29. );
  30. #else
  31. #define DbgDumpTransportAddress( r, t, a )
  32. #endif
  33. // Once a valid handle to a transport device object has been obtained subsequent
  34. // opens to the same device object can be opened with a NULL relative name to
  35. // this handle. This has two beneficial side effects --- one it is fast since
  36. // we do not have to go through the object manager's logic for parsing names and
  37. // in remote boot scenarios it minimizes the footprint that needs to be locked
  38. // down.
  39. UNICODE_STRING RelativeName = { 0,0,NULL};
  40. NTSTATUS
  41. RxTdiBindToTransport(
  42. IN OUT PRXCE_TRANSPORT pTransport)
  43. /*++
  44. Routine Description:
  45. This routine binds to the transport specified.
  46. Arguments:
  47. pTransport - the transport structure to be initialized
  48. pRxBindingContext - the binding context containing a pointer to the
  49. transport name and the quality of service for NT.
  50. Return Value:
  51. STATUS_SUCCESS - if the call was successfull.
  52. Notes:
  53. --*/
  54. {
  55. NTSTATUS Status = STATUS_SUCCESS;
  56. OBJECT_ATTRIBUTES ChannelAttributes;
  57. IO_STATUS_BLOCK IoStatusBlock;
  58. RxProfile(RxTdi,RxTdiBindToTransport);
  59. InitializeObjectAttributes(
  60. &ChannelAttributes, // Tdi Control Channel attributes
  61. &pTransport->Name, // Name
  62. OBJ_CASE_INSENSITIVE, // Attributes
  63. NULL, // RootDirectory
  64. NULL); // SecurityDescriptor
  65. Status = ZwCreateFile(
  66. &pTransport->ControlChannel, // Handle
  67. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
  68. &ChannelAttributes, // Object Attributes
  69. &IoStatusBlock, // Final I/O status block
  70. 0, // Allocation Size
  71. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  72. FILE_SHARE_READ, // Sharing attributes
  73. FILE_OPEN_IF, // Create disposition
  74. 0, // CreateOptions
  75. NULL, // EA Buffer
  76. 0); // EA length
  77. if (NT_SUCCESS(Status)) {
  78. // Obtain a referenced pointer to the file object.
  79. Status = ObReferenceObjectByHandle(
  80. pTransport->ControlChannel, // Object Handle
  81. FILE_ANY_ACCESS, // Desired Access
  82. NULL, // Object Type
  83. KernelMode, // Processor mode
  84. (PVOID *)&pTransport->pControlChannelFileObject,// Object pointer
  85. NULL); // Object Handle information
  86. if (NT_SUCCESS(Status)) {
  87. PIRP pIrp = NULL;
  88. // Obtain the related device object.
  89. pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject);
  90. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  91. if (pIrp != NULL) {
  92. PMDL pMdl;
  93. // Obtain the provider information from the specified transport.
  94. ASSERT(pTransport->pProviderInfo != NULL);
  95. pMdl = RxAllocateMdl(
  96. pTransport->pProviderInfo, // Virtual address for MDL construction
  97. sizeof( RXCE_TRANSPORT_PROVIDER_INFO)); // size of the buffer
  98. if ( pMdl != NULL ) {
  99. try {
  100. MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess );
  101. } except( EXCEPTION_EXECUTE_HANDLER ) {
  102. IoFreeMdl( pMdl );
  103. Status = GetExceptionCode();
  104. }
  105. if (Status == STATUS_SUCCESS) {
  106. TdiBuildQueryInformation(
  107. pIrp,
  108. pTransport->pDeviceObject,
  109. pTransport->pControlChannelFileObject,
  110. RxTdiRequestCompletion, // Completion routine
  111. NULL, // Completion context
  112. TDI_QUERY_PROVIDER_INFO,
  113. pMdl);
  114. Status = RxCeSubmitTdiRequest(
  115. pTransport->pDeviceObject,
  116. pIrp);
  117. MmUnlockPages(pMdl);
  118. IoFreeMdl(pMdl);
  119. }
  120. } else {
  121. Status = STATUS_INSUFFICIENT_RESOURCES;
  122. }
  123. RxCeFreeIrp(pIrp);
  124. } else {
  125. Status = STATUS_INSUFFICIENT_RESOURCES;
  126. }
  127. }
  128. }
  129. return Status;
  130. }
  131. NTSTATUS
  132. RxTdiUnbindFromTransport(
  133. IN OUT PRXCE_TRANSPORT pTransport)
  134. /*++
  135. Routine Description:
  136. This routine unbinds to the transport specified.
  137. Arguments:
  138. pTransport - the transport structure
  139. Return Value:
  140. STATUS_SUCCESS - if the call was successfull.
  141. --*/
  142. {
  143. NTSTATUS Status = STATUS_SUCCESS;
  144. RxProfile(RxTdi,RxTdiUnbindFromTransport);
  145. // Dereference the control channel file object.
  146. if (pTransport->pControlChannelFileObject != NULL) {
  147. ObDereferenceObject(pTransport->pControlChannelFileObject);
  148. }
  149. // Close the control channel
  150. if (pTransport->ControlChannel != INVALID_HANDLE_VALUE) {
  151. Status = ZwClose(pTransport->ControlChannel);
  152. }
  153. pTransport->pControlChannelFileObject = NULL;
  154. pTransport->ControlChannel = INVALID_HANDLE_VALUE;
  155. return Status;
  156. }
  157. NTSTATUS
  158. RxTdiOpenAddress(
  159. IN PRXCE_TRANSPORT pTransport,
  160. IN PTRANSPORT_ADDRESS pTransportAddress,
  161. IN OUT PRXCE_ADDRESS pAddress)
  162. /*++
  163. Routine Description:
  164. This routine opens an address object.
  165. Arguments:
  166. Return Value:
  167. STATUS_SUCCESS - if the call was successfull.
  168. --*/
  169. {
  170. NTSTATUS Status = STATUS_SUCCESS;
  171. OBJECT_ATTRIBUTES AddressAttributes;
  172. IO_STATUS_BLOCK IoStatusBlock;
  173. ULONG TransportAddressLength;
  174. ULONG TransportEaBufferLength;
  175. PFILE_FULL_EA_INFORMATION pTransportAddressEa;
  176. RxProfile(RxTdi,RxTdiOpenAddress);
  177. TransportAddressLength = ComputeTransportAddressLength(pTransportAddress);
  178. // Build an EA buffer for the specified transport address
  179. Status = BuildEaBuffer(
  180. TDI_TRANSPORT_ADDRESS_LENGTH,
  181. TdiTransportAddress,
  182. TransportAddressLength,
  183. pTransportAddress,
  184. &pTransportAddressEa,
  185. &TransportEaBufferLength);
  186. if (!NT_SUCCESS(Status)) {
  187. return Status;
  188. }
  189. InitializeObjectAttributes(
  190. &AddressAttributes, // OBJECT_ATTRIBUTES instance
  191. &RelativeName, // Name
  192. 0, // Attributes
  193. pTransport->ControlChannel, // RootDirectory
  194. NULL); // SecurityDescriptor
  195. Status = ZwCreateFile(
  196. &pAddress->hAddress, // Handle
  197. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
  198. &AddressAttributes, // Object Attributes
  199. &IoStatusBlock, // Final I/O status block
  200. 0, // Allocation Size
  201. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  202. FILE_SHARE_READ, // Sharing attributes
  203. FILE_OPEN_IF, // Create disposition
  204. 0, // CreateOptions
  205. pTransportAddressEa, // EA Buffer
  206. TransportEaBufferLength); // EA length
  207. if (NT_SUCCESS(Status)) {
  208. // Obtain a referenced pointer to the file object.
  209. Status = ObReferenceObjectByHandle (
  210. pAddress->hAddress, // Object Handle
  211. FILE_ANY_ACCESS, // Desired Access
  212. NULL, // Object Type
  213. KernelMode, // Processor mode
  214. (PVOID *)&pAddress->pFileObject, // Object pointer
  215. NULL); // Object Handle information
  216. Status = RxTdiSetEventHandlers(pTransport,pAddress);
  217. //DbgPrint("RDR opened address %lx\n", pAddress->hAddress);
  218. }
  219. // Free up the EA buffer allocated.
  220. RxFreePool(pTransportAddressEa);
  221. RxDbgTrace(0, Dbg,("RxTdiOpenAddress returns %lx\n",Status));
  222. return Status;
  223. }
  224. NTSTATUS
  225. RxTdiSetEventHandlers(
  226. PRXCE_TRANSPORT pTransport,
  227. PRXCE_ADDRESS pRxCeAddress)
  228. /*++
  229. Routine Description:
  230. This routine establishes the event handlers for a given address.
  231. Arguments:
  232. pRxCeAddress - the address object
  233. Return Value:
  234. STATUS_SUCCESS - if the call was successfull.
  235. --*/
  236. {
  237. NTSTATUS Status;
  238. PIRP pIrp;
  239. RxProfile(RxTdi,RxTdiSetEventHandlers);
  240. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  241. if (pIrp == NULL) {
  242. return STATUS_INSUFFICIENT_RESOURCES;
  243. }
  244. // The event handlers need to be set one at a time.
  245. do {
  246. // Connect Event handler
  247. TdiBuildSetEventHandler(
  248. pIrp,
  249. pTransport->pDeviceObject,
  250. pRxCeAddress->pFileObject,
  251. NULL,
  252. NULL,
  253. TDI_EVENT_CONNECT,
  254. RxTdiConnectEventHandler,
  255. pRxCeAddress);
  256. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  257. if (!NT_SUCCESS(Status)) {
  258. continue;
  259. }
  260. // Disconnect event handler
  261. TdiBuildSetEventHandler(
  262. pIrp,
  263. pTransport->pDeviceObject,
  264. pRxCeAddress->pFileObject,
  265. NULL,
  266. NULL,
  267. TDI_EVENT_DISCONNECT,
  268. RxTdiDisconnectEventHandler,
  269. pRxCeAddress);
  270. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  271. if (!NT_SUCCESS(Status)) {
  272. continue;
  273. }
  274. // Error event handler
  275. TdiBuildSetEventHandler(
  276. pIrp,
  277. pTransport->pDeviceObject,
  278. pRxCeAddress->pFileObject,
  279. NULL,
  280. NULL,
  281. TDI_EVENT_ERROR,
  282. RxTdiErrorEventHandler,
  283. pRxCeAddress);
  284. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  285. if (!NT_SUCCESS(Status)) {
  286. continue;
  287. }
  288. // Receive Event handler
  289. TdiBuildSetEventHandler(
  290. pIrp,
  291. pTransport->pDeviceObject,
  292. pRxCeAddress->pFileObject,
  293. NULL,
  294. NULL,
  295. TDI_EVENT_RECEIVE,
  296. RxTdiReceiveEventHandler,
  297. pRxCeAddress);
  298. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  299. if (!NT_SUCCESS(Status)) {
  300. continue;
  301. }
  302. #if 0
  303. // Receive datagram event handler
  304. TdiBuildSetEventHandler(
  305. pIrp,
  306. pTransport->pDeviceObject,
  307. pRxCeAddress->pFileObject,
  308. NULL,
  309. NULL,
  310. TDI_EVENT_RECEIVE_DATAGRAM,
  311. RxTdiReceiveDatagramEventHandler,
  312. pRxCeAddress);
  313. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  314. if (!NT_SUCCESS(Status)) {
  315. continue;
  316. }
  317. #endif
  318. // Receieve expedited event handler
  319. TdiBuildSetEventHandler(
  320. pIrp,
  321. pTransport->pDeviceObject,
  322. pRxCeAddress->pFileObject,
  323. NULL,
  324. NULL,
  325. TDI_EVENT_RECEIVE_EXPEDITED,
  326. RxTdiReceiveExpeditedEventHandler,
  327. pRxCeAddress);
  328. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  329. if (!NT_SUCCESS(Status)) {
  330. continue;
  331. }
  332. #if 0
  333. // Send possible event handler
  334. TdiBuildSetEventHandler(
  335. pIrp,
  336. pTransport->pDeviceObject,
  337. pRxCeAddress->pFileObject,
  338. NULL,
  339. NULL,
  340. TDI_EVENT_SEND_POSSIBLE,
  341. RxTdiSendPossibleEventHandler,
  342. RxCeGetAddressHandle(pRxCeAddress));
  343. Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
  344. #endif
  345. if (NT_SUCCESS(Status)) {
  346. // All the event handlers have been successfully set.
  347. break;
  348. }
  349. } while (NT_SUCCESS(Status));
  350. // Free the Irp
  351. RxCeFreeIrp(pIrp);
  352. return Status;
  353. }
  354. NTSTATUS
  355. RxTdiConnect(
  356. IN PRXCE_TRANSPORT pTransport,
  357. IN OUT PRXCE_ADDRESS pAddress,
  358. IN OUT PRXCE_CONNECTION pConnection,
  359. IN OUT PRXCE_VC pVc)
  360. /*++
  361. Routine Description:
  362. This routine establishes a connection between a local connection endpoint and
  363. a remote transport address.
  364. Arguments:
  365. pTransport - the associated transport
  366. pAddress - the address object to be closed
  367. pConnection - the RxCe connection instance
  368. pVc - the RxCe virtual circuit instance.
  369. Return Value:
  370. STATUS_SUCCESS - if the call was successfull.
  371. --*/
  372. {
  373. NTSTATUS Status = STATUS_SUCCESS;
  374. OBJECT_ATTRIBUTES VcAttributes;
  375. IO_STATUS_BLOCK IoStatusBlock;
  376. PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL;
  377. ULONG ConnectionContextEaBufferLength;
  378. PFILE_FULL_EA_INFORMATION pConnectionContextEa;
  379. RxProfile(RxTdi,RxTdiConnect);
  380. #if DBG
  381. {
  382. PTRANSPORT_ADDRESS pTA =
  383. (PTRANSPORT_ADDRESS)(pConnection->pConnectionInformation->RemoteAddress);
  384. RxDbgTrace(0, Dbg,("RxTdiConnect to %wZ address length %d type %d\n",
  385. &(pTransport->Name),
  386. pTA->Address[0].AddressLength,
  387. pTA->Address[0].AddressType ));
  388. }
  389. #endif
  390. // Build an EA buffer for the specified connection context
  391. Status = BuildEaBuffer(
  392. TDI_CONNECTION_CONTEXT_LENGTH,
  393. TdiConnectionContext,
  394. sizeof(PRXCE_VC),
  395. &pVc,
  396. &pConnectionContextEa,
  397. &ConnectionContextEaBufferLength);
  398. if (!NT_SUCCESS(Status)) {
  399. return Status;
  400. }
  401. // Open the local connection endpoint.
  402. InitializeObjectAttributes(
  403. &VcAttributes, // OBJECT_ATTRIBUTES instance
  404. &RelativeName, // Name
  405. 0, // Attributes
  406. pTransport->ControlChannel, // RootDirectory
  407. NULL); // SecurityDescriptor
  408. Status = ZwCreateFile(
  409. &pVc->hEndpoint, // Handle
  410. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
  411. &VcAttributes, // Object Attributes
  412. &IoStatusBlock, // Final I/O status block
  413. 0, // Allocation Size
  414. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  415. FILE_SHARE_READ, // Sharing attributes
  416. FILE_OPEN_IF, // Create disposition
  417. 0, // CreateOptions
  418. pConnectionContextEa, // EA Buffer
  419. ConnectionContextEaBufferLength); // EA length
  420. if (NT_SUCCESS(Status)) {
  421. PIRP pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  422. if (pIrp != NULL) {
  423. // Obtain a referenced pointer to the file object.
  424. Status = ObReferenceObjectByHandle (
  425. pVc->hEndpoint, // Object Handle
  426. FILE_ANY_ACCESS, // Desired Access
  427. NULL, // Object Type
  428. KernelMode, // Processor mode
  429. (PVOID *)&pVc->pEndpointFileObject, // Object pointer
  430. NULL); // Object Handle information
  431. if (NT_SUCCESS(Status)) {
  432. // Associate the local endpoint with the address object.
  433. TdiBuildAssociateAddress(
  434. pIrp,
  435. pTransport->pDeviceObject,
  436. pVc->pEndpointFileObject,
  437. NULL,
  438. NULL,
  439. pAddress->hAddress);
  440. Status = RxCeSubmitTdiRequest(
  441. pTransport->pDeviceObject,
  442. pIrp);
  443. if (NT_SUCCESS(Status)) {
  444. // issue the connect request to the underlying transport provider.
  445. TdiBuildConnect(
  446. pIrp,
  447. pTransport->pDeviceObject,
  448. pVc->pEndpointFileObject,
  449. NULL,
  450. NULL,
  451. &ConnectionTimeOut,
  452. pConnection->pConnectionInformation,
  453. pReturnConnectionInformation);
  454. Status = RxCeSubmitTdiRequest(
  455. pTransport->pDeviceObject,
  456. pIrp);
  457. if (!NT_SUCCESS(Status)) {
  458. // Disassociate address from the connection since the connect request was
  459. // not successful.
  460. NTSTATUS LocalStatus;
  461. TdiBuildDisassociateAddress(
  462. pIrp,
  463. pTransport->pDeviceObject,
  464. pVc->pEndpointFileObject,
  465. NULL,
  466. NULL);
  467. LocalStatus = RxCeSubmitTdiRequest(
  468. pTransport->pDeviceObject,
  469. pIrp);
  470. } else {
  471. // The associate address was not successful.
  472. RxDbgTrace(0, Dbg,("TDI connect returned %lx\n",Status));
  473. }
  474. } else {
  475. // The associate address was not successful.
  476. RxDbgTrace(0, Dbg,("TDI associate address returned %lx\n",Status));
  477. }
  478. if (!NT_SUCCESS(Status)) {
  479. // Dereference the endpoint file object.
  480. ObDereferenceObject(pVc->pEndpointFileObject);
  481. }
  482. } else {
  483. // error obtaining the file object for the connection.
  484. RxDbgTrace(0, Dbg,("error referencing endpoint file object %lx\n",Status));
  485. }
  486. RxCeFreeIrp(pIrp);
  487. if (!NT_SUCCESS(Status)) {
  488. // Close the endpoint file object handle
  489. ZwClose(pVc->hEndpoint);
  490. }
  491. } else {
  492. Status = STATUS_INSUFFICIENT_RESOURCES;
  493. }
  494. } else {
  495. // error creating the connection object
  496. RxDbgTrace(0, Dbg,("Connection object(ZwCreate) returned %lx\n",Status));
  497. }
  498. if (!NT_SUCCESS(Status)) {
  499. pVc->hEndpoint = INVALID_HANDLE_VALUE;
  500. pVc->pEndpointFileObject = NULL;
  501. }
  502. RxFreePool(pConnectionContextEa);
  503. return Status;
  504. }
  505. NTSTATUS
  506. RxTdiDereferenceAndFreeIrp(
  507. IN PULONG IrpRefCount,
  508. IN PIRP pIrp)
  509. /*++
  510. Routine Description:
  511. This routine dereference the connect Irp and free it if ref count reaches 0
  512. Arguments:
  513. pParameters - the connection parameters
  514. Return Value:
  515. STATUS_SUCCESS - if the call was successfull.
  516. --*/
  517. {
  518. ULONG RefCount;
  519. RefCount = InterlockedDecrement(IrpRefCount);
  520. if (RefCount == 0) {
  521. RxCeFreeIrp(pIrp);
  522. RxFreePool(IrpRefCount);
  523. }
  524. return STATUS_SUCCESS;
  525. }
  526. NTSTATUS
  527. RxTdiAsynchronousConnectCompletion(
  528. IN PDEVICE_OBJECT DeviceObject,
  529. IN PIRP pIrp,
  530. IN PVOID Context)
  531. /*++
  532. Routine Description:
  533. This routine completes an asynchronous connect request.
  534. Arguments:
  535. pDeviceObject - the device object
  536. pIrp - the IRp
  537. Context - the completion context
  538. Return Value:
  539. STATUS_SUCCESS - if the call was successfull.
  540. --*/
  541. {
  542. PULONG IrpRefCount = NULL;
  543. PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters;
  544. RxDbgTrace(0, Dbg,("RxTdiAsynchronousConnectCompletion, irp 0x%x, status 0x%x\n",
  545. pIrp, pIrp->IoStatus.Status));
  546. pParameters = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)Context;
  547. pParameters->CallOutStatus = pIrp->IoStatus.Status;
  548. IrpRefCount = pParameters->IrpRefCount;
  549. RxWmiLogError(pParameters->CallOutStatus,
  550. LOG,
  551. RxTdiAsynchronousConnectCompletion,
  552. LOGULONG(pParameters->CallOutStatus)
  553. LOGUSTR(pParameters->Connection.pAddress->pTransport->Name));
  554. if (pParameters->pCallOutContext != NULL) {
  555. pParameters->pCallOutContext->pRxCallOutCompletion(
  556. (PRX_CALLOUT_PARAMETERS_BLOCK)pParameters);
  557. }
  558. // Free the IRP.
  559. RxTdiDereferenceAndFreeIrp(IrpRefCount,pIrp);
  560. return STATUS_MORE_PROCESSING_REQUIRED;
  561. UNREFERENCED_PARAMETER( DeviceObject );
  562. }
  563. NTSTATUS
  564. RxTdiCancelAsynchronousConnect(
  565. IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters)
  566. /*++
  567. Routine Description:
  568. This routine cancels a connection between a local connection endpoint and
  569. a remote transport address.
  570. Arguments:
  571. pParameters - the connection parameters
  572. Return Value:
  573. STATUS_CANCELLED - if the call was successfull.
  574. --*/
  575. {
  576. KIRQL OldIrql;
  577. PIRP pIrp = NULL;
  578. PULONG IrpRefCount = NULL;
  579. BOOLEAN ShouldCancel = FALSE;
  580. NTSTATUS Status = STATUS_PENDING;
  581. KeAcquireSpinLock(&pParameters->pCallOutContext->SpinLock,&OldIrql);
  582. pIrp = InterlockedExchangePointer(
  583. &pParameters->pConnectIrp,
  584. CANCELLED_CONNECT_IRP);
  585. if ((pIrp != NULL) && (pIrp != CANCELLED_CONNECT_IRP)) {
  586. IrpRefCount = pParameters->IrpRefCount;
  587. (*IrpRefCount) ++;
  588. ShouldCancel = TRUE;
  589. }
  590. KeReleaseSpinLock(&pParameters->pCallOutContext->SpinLock,OldIrql);
  591. if (ShouldCancel) {
  592. if (IoCancelIrp(pIrp)) {
  593. Status = STATUS_CANCELLED;
  594. }
  595. RxTdiDereferenceAndFreeIrp(IrpRefCount,pIrp);
  596. }
  597. return Status;
  598. }
  599. NTSTATUS
  600. RxTdiCleanupAsynchronousConnect(
  601. IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters)
  602. /*++
  603. Routine Description:
  604. This routine disconnects all failed requests when asynchronous connection attempts
  605. are made.
  606. Arguments:
  607. pParameters - the connection parameters
  608. Return Value:
  609. STATUS_SUCCESS - if the call was successfull.
  610. --*/
  611. {
  612. NTSTATUS Status = STATUS_SUCCESS;
  613. PIRP pIrp;
  614. PRXCE_CONNECTION pConnection;
  615. PRXCE_VC pVc;
  616. RxProfile(RxTdi,RxTdiConnect);
  617. pConnection = &pParameters->Connection;
  618. pVc = &pParameters->Vc;
  619. RxProfile(RxTdi,RxTdiDisconnect);
  620. if (pVc->pEndpointFileObject != NULL) {
  621. PDEVICE_OBJECT pDeviceObject;
  622. pDeviceObject = IoGetRelatedDeviceObject(pVc->pEndpointFileObject);
  623. pIrp = RxCeAllocateIrp(pDeviceObject->StackSize,FALSE);
  624. if (pIrp != NULL) {
  625. TdiBuildDisassociateAddress(
  626. pIrp,
  627. pDeviceObject,
  628. pVc->pEndpointFileObject,
  629. NULL,
  630. NULL);
  631. Status = RxCeSubmitTdiRequest(
  632. pDeviceObject,
  633. pIrp);
  634. if (Status != STATUS_SUCCESS) {
  635. RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disassociate returned %lx\n",Status));
  636. }
  637. if (pParameters->CallOutStatus == STATUS_SUCCESS) {
  638. // Build the disconnect request to the underlying transport driver
  639. TdiBuildDisconnect(
  640. pIrp, // the IRP
  641. pDeviceObject, // the device object
  642. pVc->pEndpointFileObject, // the connection (VC) file object
  643. NULL, // Completion routine
  644. NULL, // completion context
  645. NULL, // time
  646. RXCE_DISCONNECT_ABORT, // disconnect options
  647. pConnection->pConnectionInformation, // disconnect request connection information
  648. NULL); // disconnect return connection information
  649. Status = RxCeSubmitTdiRequest(
  650. pDeviceObject,
  651. pIrp);
  652. if (!NT_SUCCESS(Status)) {
  653. RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disconnect returned %lx\n",Status));
  654. }
  655. }
  656. RxCeFreeIrp(pIrp);
  657. }
  658. // Dereference the endpoint file object.
  659. ObDereferenceObject(pVc->pEndpointFileObject);
  660. // Close the endpoint file object handle
  661. ZwClose(pVc->hEndpoint);
  662. pVc->pEndpointFileObject = NULL;
  663. pVc->hEndpoint = INVALID_HANDLE_VALUE;
  664. }
  665. return STATUS_SUCCESS;
  666. }
  667. NTSTATUS
  668. RxTdiInitiateAsynchronousConnect(
  669. IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters)
  670. /*++
  671. Routine Description:
  672. This routine establishes a connection between a local connection endpoint and
  673. a remote transport address.
  674. Arguments:
  675. pParameters - the connection parameters
  676. Return Value:
  677. STATUS_SUCCESS - if the call was successfull.
  678. --*/
  679. {
  680. NTSTATUS Status = STATUS_SUCCESS;
  681. PRXCE_TRANSPORT pTransport;
  682. PRXCE_ADDRESS pAddress;
  683. PRXCE_CONNECTION pConnection;
  684. PRXCE_VC pVc;
  685. OBJECT_ATTRIBUTES VcAttributes;
  686. IO_STATUS_BLOCK IoStatusBlock;
  687. PIRP pIrp = NULL;
  688. PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL;
  689. PFILE_FULL_EA_INFORMATION pConnectionContextEa;
  690. ULONG ConnectionContextEaBufferLength;
  691. PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pContext;
  692. RxProfile(RxTdi,RxTdiConnect);
  693. pConnection = &pParameters->Connection;
  694. pVc = &pParameters->Vc;
  695. pVc->hEndpoint = INVALID_HANDLE_VALUE;
  696. pVc->pEndpointFileObject = NULL;
  697. if (pParameters->pConnectIrp == CANCELLED_CONNECT_IRP) {
  698. return STATUS_CANCELLED;
  699. }
  700. pParameters->IrpRefCount = (PULONG)RxAllocatePoolWithTag(
  701. NonPagedPool,
  702. sizeof(ULONG),
  703. RXCE_CONNECTION_POOLTAG);
  704. if (pParameters->IrpRefCount == NULL) {
  705. return STATUS_INSUFFICIENT_RESOURCES;
  706. }
  707. *(pParameters->IrpRefCount) = 1;
  708. pContext = (PRX_CREATE_CONNECTION_CALLOUT_CONTEXT)pParameters->pCallOutContext;
  709. pAddress = pConnection->pAddress;
  710. pTransport = pAddress->pTransport;
  711. DbgDumpTransportAddress(
  712. L"RxInitiateAsynchronousConnect",
  713. pTransport,
  714. (PTRANSPORT_ADDRESS)(pConnection->pConnectionInformation->RemoteAddress)
  715. );
  716. // Build an EA buffer for the specified connection context
  717. Status = BuildEaBuffer(
  718. TDI_CONNECTION_CONTEXT_LENGTH,
  719. TdiConnectionContext,
  720. sizeof(PRXCE_VC),
  721. &pContext->pConnectionContext,
  722. &pConnectionContextEa,
  723. &ConnectionContextEaBufferLength);
  724. if (!NT_SUCCESS(Status)) {
  725. if (pParameters->IrpRefCount != NULL) {
  726. RxFreePool(pParameters->IrpRefCount);
  727. pParameters->IrpRefCount = NULL;
  728. }
  729. return Status;
  730. }
  731. // Open the local connection endpoint.
  732. InitializeObjectAttributes(
  733. &VcAttributes, // OBJECT_ATTRIBUTES instance
  734. &RelativeName, // Name
  735. 0, // Attributes
  736. pTransport->ControlChannel, // RootDirectory
  737. NULL); // SecurityDescriptor
  738. Status = ZwCreateFile(
  739. &pVc->hEndpoint, // Handle
  740. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
  741. &VcAttributes, // Object Attributes
  742. &IoStatusBlock, // Final I/O status block
  743. 0, // Allocation Size
  744. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  745. FILE_SHARE_READ, // Sharing attributes
  746. FILE_OPEN_IF, // Create disposition
  747. 0, // CreateOptions
  748. pConnectionContextEa, // EA Buffer
  749. ConnectionContextEaBufferLength); // EA length
  750. // Free the connection context ea buffer.
  751. RxFreePool(pConnectionContextEa);
  752. if (NT_SUCCESS(Status)) {
  753. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  754. if (pIrp != NULL) {
  755. // Obtain a referenced pointer to the file object.
  756. Status = ObReferenceObjectByHandle (
  757. pVc->hEndpoint, // Object Handle
  758. FILE_ANY_ACCESS, // Desired Access
  759. NULL, // Object Type
  760. KernelMode, // Processor mode
  761. (PVOID *)&pVc->pEndpointFileObject, // Object pointer
  762. NULL); // Object Handle information
  763. if (NT_SUCCESS(Status)) {
  764. // Associate the local endpoint with the address object.
  765. TdiBuildAssociateAddress(
  766. pIrp,
  767. pTransport->pDeviceObject,
  768. pVc->pEndpointFileObject,
  769. NULL,
  770. NULL,
  771. pAddress->hAddress);
  772. Status = RxCeSubmitTdiRequest(
  773. pTransport->pDeviceObject,
  774. pIrp);
  775. if (NT_SUCCESS(Status)) {
  776. // issue the connect request to the underlying transport provider.
  777. TdiBuildConnect(
  778. pIrp,
  779. pTransport->pDeviceObject,
  780. pVc->pEndpointFileObject,
  781. NULL,
  782. NULL,
  783. &ConnectionTimeOut,
  784. pConnection->pConnectionInformation,
  785. pReturnConnectionInformation);
  786. IoSetCompletionRoutine(
  787. pIrp, // The IRP
  788. RxTdiAsynchronousConnectCompletion, // The completion routine
  789. pParameters, // The completion context
  790. TRUE, // Invoke On Success
  791. TRUE, // Invoke On Error
  792. TRUE); // Invoke On Cancel
  793. InterlockedExchangePointer(
  794. &pParameters->pConnectIrp,
  795. pIrp);
  796. // Submit the request
  797. Status = IoCallDriver(
  798. pTransport->pDeviceObject,
  799. pIrp);
  800. if (!NT_SUCCESS(Status)) {
  801. RxDbgTrace(0,Dbg,("RxTdiAsynchronousConnect: Connect IRP initiation failed, irp %lx, status 0x%x\n",pIrp, Status));
  802. }
  803. Status = STATUS_PENDING;
  804. } else {
  805. // The associate address was not successful.
  806. RxDbgTrace(0, Dbg,("TDI associate address returned %lx\n",Status));
  807. }
  808. } else {
  809. // error obtaining the file object for the connection.
  810. RxDbgTrace(0, Dbg,("error referencing endpoint file object %lx\n",Status));
  811. }
  812. } else {
  813. Status = STATUS_INSUFFICIENT_RESOURCES;
  814. }
  815. if (Status != STATUS_PENDING) {
  816. if (pIrp != NULL) {
  817. RxCeFreeIrp(pIrp);
  818. }
  819. if (pParameters->IrpRefCount != NULL) {
  820. RxFreePool(pParameters->IrpRefCount);
  821. }
  822. if (pVc->pEndpointFileObject != NULL) {
  823. ObDereferenceObject(pVc->pEndpointFileObject);
  824. pVc->pEndpointFileObject = NULL;
  825. }
  826. if (pVc->hEndpoint != INVALID_HANDLE_VALUE) {
  827. // Close the endpoint file object handle
  828. ZwClose(pVc->hEndpoint);
  829. pVc->hEndpoint = INVALID_HANDLE_VALUE;
  830. }
  831. }
  832. } else {
  833. // error creating the connection object
  834. RxDbgTrace(0, Dbg,("Connection object(ZwCreate) returned %lx\n",Status));
  835. if (pParameters->IrpRefCount != NULL) {
  836. RxFreePool(pParameters->IrpRefCount);
  837. pParameters->IrpRefCount = NULL;
  838. }
  839. }
  840. return Status;
  841. }
  842. NTSTATUS
  843. RxTdiReconnect(
  844. IN PRXCE_TRANSPORT pTransport,
  845. IN OUT PRXCE_ADDRESS pAddress,
  846. IN OUT PRXCE_CONNECTION pConnection,
  847. IN OUT PRXCE_VC pVc)
  848. /*++
  849. Routine Description:
  850. This routine establishes a connection between a local connection endpoint and
  851. a remote transport address.
  852. Arguments:
  853. pTransport - the associated transport
  854. pAddress - the address object to be closed
  855. pConnection - the RxCe connection instance
  856. pVc - the RxCe virtual circuit instance.
  857. Return Value:
  858. STATUS_SUCCESS - if the call was successfull.
  859. --*/
  860. {
  861. NTSTATUS Status;
  862. PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL;
  863. PIRP pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  864. RxProfile(RxTdi,RxTdiReconnect);
  865. ASSERT(pVc->State == RXCE_VC_DISCONNECTED);
  866. if (pIrp != NULL) {
  867. // issue the connect request to the underlying transport provider.
  868. TdiBuildConnect(
  869. pIrp,
  870. pTransport->pDeviceObject,
  871. pVc->pEndpointFileObject,
  872. NULL,
  873. NULL,
  874. &ConnectionTimeOut,
  875. pConnection->pConnectionInformation,
  876. pReturnConnectionInformation);
  877. Status = RxCeSubmitTdiRequest(
  878. pTransport->pDeviceObject,
  879. pIrp);
  880. if (NT_SUCCESS(Status)) {
  881. InterlockedExchange(
  882. &pVc->State,
  883. RXCE_VC_ACTIVE);
  884. } else {
  885. // The reconnect request was not successful
  886. RxDbgTrace(0, Dbg,("RxTdiReconnect: TDI connect returned %lx\n",Status));
  887. }
  888. RxCeFreeIrp(pIrp);
  889. } else {
  890. Status = STATUS_INSUFFICIENT_RESOURCES;
  891. }
  892. return Status;
  893. }
  894. NTSTATUS
  895. RxTdiDisconnect(
  896. IN PRXCE_TRANSPORT pTransport,
  897. IN PRXCE_ADDRESS pAddress,
  898. IN PRXCE_CONNECTION pConnection,
  899. IN PRXCE_VC pVc,
  900. IN ULONG DisconnectFlags)
  901. /*++
  902. Routine Description:
  903. This routine closes down a previously established connection.
  904. Arguments:
  905. pTransport - the associated transport
  906. pAddress - the address object
  907. pConnection - the connection
  908. pVc - the virtual circuit to be disconnected.
  909. DisconnectFlags - DisconnectOptions
  910. Return Value:
  911. STATUS_SUCCESS - if the call was successfull.
  912. --*/
  913. {
  914. NTSTATUS Status;
  915. PIRP pIrp;
  916. RxProfile(RxTdi,RxTdiDisconnect);
  917. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  918. if (pIrp == NULL) {
  919. return STATUS_INSUFFICIENT_RESOURCES;
  920. }
  921. TdiBuildDisassociateAddress(
  922. pIrp,
  923. pTransport->pDeviceObject,
  924. pVc->pEndpointFileObject,
  925. NULL,
  926. NULL);
  927. Status = RxCeSubmitTdiRequest(
  928. pTransport->pDeviceObject,
  929. pIrp);
  930. if (NT_SUCCESS(Status)) {
  931. // Build the disconnect request to the underlying transport driver
  932. TdiBuildDisconnect(
  933. pIrp, // the IRP
  934. pTransport->pDeviceObject, // the device object
  935. pVc->pEndpointFileObject, // the connection (VC) file object
  936. NULL, // Completion routine
  937. NULL, // completion context
  938. NULL, // time
  939. DisconnectFlags, // disconnect options
  940. pConnection->pConnectionInformation, // disconnect request connection information
  941. NULL); // disconnect return connection information
  942. Status = RxCeSubmitTdiRequest(
  943. pTransport->pDeviceObject,
  944. pIrp);
  945. if (!NT_SUCCESS(Status)) {
  946. RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disconnect returned %lx\n",Status));
  947. }
  948. } else {
  949. RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disassociate returned %lx\n",Status));
  950. }
  951. RxCeFreeIrp(pIrp);
  952. return STATUS_SUCCESS;
  953. }
  954. NTSTATUS
  955. RxTdiCloseAddress(
  956. IN OUT PRXCE_ADDRESS pAddress)
  957. /*++
  958. Routine Description:
  959. This routine closes the address object.
  960. Arguments:
  961. pRxCeAddress - the address object to be closed
  962. Return Value:
  963. STATUS_SUCCESS - if the call was successfull.
  964. --*/
  965. {
  966. NTSTATUS Status = STATUS_SUCCESS;
  967. // Dereference the file object.
  968. if (pAddress->pFileObject != NULL) {
  969. ObDereferenceObject(pAddress->pFileObject);
  970. }
  971. // Close the address file object handle
  972. ZwClose(pAddress->hAddress);
  973. //DbgPrint("RDR closed address %lx\n", pAddress->hAddress);
  974. return Status;
  975. }
  976. NTSTATUS
  977. RxTdiQueryInformation(
  978. IN PRXCE_TRANSPORT pTransport,
  979. IN PRXCE_ADDRESS pAddress,
  980. IN PRXCE_CONNECTION pConnection,
  981. IN PRXCE_VC pVc,
  982. IN ULONG QueryType,
  983. IN PVOID pQueryBuffer,
  984. IN ULONG QueryBufferLength)
  985. /*++
  986. Routine Description:
  987. This routine queries the information w.r.t a connection
  988. Arguments:
  989. pTransport - the associated transport
  990. pAddress - the address object to be closed
  991. pConnection - the RxCe connection instance
  992. pVc - the VC instance
  993. QueryType - the class of information desired
  994. pQueryBuffer - the buffer in whihc the data is to be returned
  995. QueryBufferLength - the query buffer length.
  996. Return Value:
  997. STATUS_SUCCESS - if the call was successfull.
  998. --*/
  999. {
  1000. NTSTATUS Status = STATUS_SUCCESS;
  1001. PIRP pIrp = NULL;
  1002. // Obtain the related device object.
  1003. pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject);
  1004. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  1005. if (pIrp != NULL) {
  1006. PMDL pMdl;
  1007. pMdl = RxAllocateMdl(
  1008. pQueryBuffer, // Virtual address for MDL construction
  1009. QueryBufferLength); // size of the buffer
  1010. if ( pMdl != NULL ) {
  1011. try {
  1012. MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess );
  1013. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1014. IoFreeMdl( pMdl );
  1015. Status = GetExceptionCode();
  1016. }
  1017. if (Status == STATUS_SUCCESS) {
  1018. // Get the file object associated with trhe connection.
  1019. TdiBuildQueryInformation(
  1020. pIrp,
  1021. pTransport->pDeviceObject,
  1022. pVc->pEndpointFileObject,
  1023. RxTdiRequestCompletion, // Completion routine
  1024. NULL, // Completion context
  1025. QueryType,
  1026. pMdl);
  1027. Status = RxCeSubmitTdiRequest(
  1028. pTransport->pDeviceObject,
  1029. pIrp);
  1030. MmUnlockPages(pMdl);
  1031. IoFreeMdl(pMdl);
  1032. }
  1033. } else {
  1034. Status = STATUS_INSUFFICIENT_RESOURCES;
  1035. }
  1036. RxCeFreeIrp(pIrp);
  1037. } else {
  1038. Status = STATUS_INSUFFICIENT_RESOURCES;
  1039. }
  1040. return Status;
  1041. }
  1042. NTSTATUS
  1043. RxTdiQueryAdapterStatus(
  1044. IN PRXCE_TRANSPORT pTransport,
  1045. IN PADAPTER_STATUS pAdapterStatus)
  1046. /*++
  1047. Routine Description:
  1048. This routine queries the information w.r.t a connection
  1049. Arguments:
  1050. pTransport - the associated transport
  1051. pAdapterStatus - ADAPTER STATUS structure
  1052. Return Value:
  1053. STATUS_SUCCESS - if the call was successfull.
  1054. --*/
  1055. {
  1056. NTSTATUS Status = STATUS_SUCCESS;
  1057. PIRP pIrp = NULL;
  1058. if (pTransport->pControlChannelFileObject != NULL) {
  1059. // Obtain the related device object.
  1060. pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject);
  1061. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  1062. if (pIrp != NULL) {
  1063. PMDL pMdl;
  1064. pMdl = RxAllocateMdl(
  1065. pAdapterStatus, // Virtual address for MDL construction
  1066. sizeof(ADAPTER_STATUS)); // size of the buffer
  1067. if ( pMdl != NULL ) {
  1068. try {
  1069. MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess );
  1070. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1071. IoFreeMdl( pMdl );
  1072. Status = GetExceptionCode();
  1073. }
  1074. if (NT_SUCCESS(Status)) {
  1075. // Get the file object associated with the connection.
  1076. TdiBuildQueryInformation(
  1077. pIrp,
  1078. pTransport->pDeviceObject,
  1079. pTransport->pControlChannelFileObject,
  1080. NULL, // Completion routine
  1081. NULL, // Completion context
  1082. TDI_QUERY_ADAPTER_STATUS,
  1083. pMdl);
  1084. Status = RxCeSubmitTdiRequest(
  1085. pTransport->pDeviceObject,
  1086. pIrp);
  1087. MmUnlockPages(pMdl);
  1088. IoFreeMdl(pMdl);
  1089. }
  1090. } else {
  1091. Status = STATUS_INSUFFICIENT_RESOURCES;
  1092. }
  1093. RxCeFreeIrp(pIrp);
  1094. } else {
  1095. Status = STATUS_INSUFFICIENT_RESOURCES;
  1096. }
  1097. } else {
  1098. Status = STATUS_ADDRESS_NOT_ASSOCIATED;
  1099. }
  1100. return Status;
  1101. }
  1102. NTSTATUS
  1103. RxTdiSend(
  1104. IN PRXCE_TRANSPORT pTransport,
  1105. IN PRXCE_ADDRESS pAddress,
  1106. IN PRXCE_CONNECTION pConnection,
  1107. IN PRXCE_VC pVc,
  1108. IN ULONG SendOptions,
  1109. IN PMDL pMdl,
  1110. IN ULONG SendLength,
  1111. IN PVOID pCompletionContext)
  1112. /*++
  1113. Routine Description:
  1114. This routine closes down a previously established connection.
  1115. Arguments:
  1116. pTransport - the associated transport
  1117. pAddress - the address object
  1118. pConnection - the connection
  1119. pVc - the virtual circuit to be disconnected.
  1120. SendOptions - the options for transmitting the data
  1121. pMdl - the buffer to be transmitted.
  1122. SendLength - length of data to be transmitted
  1123. Return Value:
  1124. STATUS_SUCCESS - if the call was successfull.
  1125. --*/
  1126. {
  1127. NTSTATUS Status = STATUS_SUCCESS;
  1128. PMDL pPartialMdl = NULL;
  1129. ULONG MdlByteCount = MmGetMdlByteCount(pMdl);
  1130. PVOID pMdlAddress = MmGetMdlVirtualAddress(pMdl);
  1131. ULONG TdiOptions = (~RXCE_FLAGS_MASK & SendOptions);
  1132. BOOLEAN SynchronousSend = ((SendOptions & RXCE_SEND_SYNCHRONOUS) != 0);
  1133. RxProfile(RxTdi,RxTdiSend);
  1134. ASSERT(pMdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_SOURCE_IS_NONPAGED_POOL|MDL_PARTIAL));
  1135. if (SendOptions & RXCE_SEND_PARTIAL) {
  1136. if (MdlByteCount > SendLength) {
  1137. pPartialMdl = IoAllocateMdl(pMdlAddress,SendLength,FALSE,FALSE,NULL);
  1138. if (pPartialMdl == NULL) {
  1139. Status = STATUS_INSUFFICIENT_RESOURCES;
  1140. } else {
  1141. RxBuildPartialHeaderMdl(pMdl,pPartialMdl,pMdlAddress,SendLength);
  1142. }
  1143. } else if (MdlByteCount == SendLength) {
  1144. // No need to build a partial MDL, reuse the MDl
  1145. pPartialMdl = pMdl;
  1146. } else {
  1147. ASSERT(!"MdlByteCount > SendLength");
  1148. return STATUS_INVALID_PARAMETER;
  1149. }
  1150. } else {
  1151. pPartialMdl = pMdl;
  1152. }
  1153. if (NT_SUCCESS(Status)) {
  1154. PIRP pIrp = NULL;
  1155. PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext = NULL;
  1156. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  1157. if (pIrp != NULL) {
  1158. // Build the Send request to the underlying transport driver
  1159. TdiBuildSend(
  1160. pIrp, // the IRP
  1161. pTransport->pDeviceObject, // the device object
  1162. pVc->pEndpointFileObject, // the connection (VC) file object
  1163. NULL, // Completion routine
  1164. NULL, // completion context
  1165. pPartialMdl, // the data buffer
  1166. TdiOptions, // send flags
  1167. SendLength); // send buffer length
  1168. if (SynchronousSend) {
  1169. // Synchronous Send Request
  1170. Status = RxCeSubmitTdiRequest(
  1171. pTransport->pDeviceObject,
  1172. pIrp);
  1173. if ((pConnection->pHandler != NULL) &&
  1174. (pConnection->pHandler->RxCeSendCompleteEventHandler != NULL)) {
  1175. (pConnection->pHandler->RxCeSendCompleteEventHandler)(
  1176. pConnection->pContext,
  1177. pVc,
  1178. pCompletionContext,
  1179. pIrp->IoStatus.Status);
  1180. }
  1181. } else {
  1182. // Aysnchronous Send Request
  1183. // CODE.IMPROVEMENT The assertion needs to be strengthened after
  1184. // max command enfocement is in place.
  1185. // (pCompletionContext != NULL) && // the caller provided a valid context
  1186. ASSERT((pConnection->pHandler != NULL) && // the connection has a handler
  1187. (pConnection->pHandler->RxCeSendCompleteEventHandler != NULL));
  1188. pRequestContext = (PRXTDI_REQUEST_COMPLETION_CONTEXT)
  1189. RxAllocatePoolWithTag(
  1190. NonPagedPool,
  1191. sizeof(RXTDI_REQUEST_COMPLETION_CONTEXT),
  1192. RXCE_TDI_POOLTAG);
  1193. if (pRequestContext != NULL) {
  1194. if (pPartialMdl != pMdl) {
  1195. pRequestContext->pPartialMdl = pPartialMdl;
  1196. } else {
  1197. pRequestContext->pPartialMdl = NULL;
  1198. }
  1199. pRequestContext->pVc = pVc;
  1200. pRequestContext->pCompletionContext = pCompletionContext;
  1201. pRequestContext->ConnectionSendCompletionHandler = pConnection->pHandler->RxCeSendCompleteEventHandler;
  1202. pRequestContext->pEventContext = pConnection->pContext;
  1203. Status = RxCeSubmitAsynchronousTdiRequest(
  1204. pTransport->pDeviceObject,
  1205. pIrp,
  1206. pRequestContext);
  1207. } else {
  1208. Status = STATUS_INSUFFICIENT_RESOURCES;
  1209. }
  1210. }
  1211. } else {
  1212. // Could not allocate the IRP.
  1213. Status = STATUS_INSUFFICIENT_RESOURCES;
  1214. }
  1215. if (SynchronousSend) {
  1216. if (pPartialMdl != pMdl) {
  1217. IoFreeMdl( pPartialMdl );
  1218. }
  1219. if (pRequestContext != NULL) {
  1220. RxFreePool(pRequestContext);
  1221. }
  1222. if (pIrp != NULL) {
  1223. RxCeFreeIrp(pIrp);
  1224. }
  1225. } else {
  1226. if( Status != STATUS_PENDING &&
  1227. pPartialMdl != pMdl ) {
  1228. IoFreeMdl( pPartialMdl );
  1229. }
  1230. // if (pIrp != NULL && Status != STATUS_PENDING) {
  1231. // DbgPrint("RDBSS AsyncSendReq returned %x %x\n", pIrp,Status);
  1232. // DbgBreakPoint();
  1233. // }
  1234. }
  1235. }
  1236. return Status;
  1237. }
  1238. NTSTATUS
  1239. RxTdiSendDatagram(
  1240. IN PRXCE_TRANSPORT pTransport,
  1241. IN PRXCE_ADDRESS pAddress,
  1242. IN PRXCE_CONNECTION_INFORMATION pConnectionInformation,
  1243. IN ULONG Options,
  1244. IN PMDL pMdl,
  1245. IN ULONG SendLength,
  1246. IN PVOID pCompletionContext)
  1247. /*++
  1248. Routine Description:
  1249. This routine closes down a previously established connection.
  1250. Arguments:
  1251. pTransport - the associated transport
  1252. pAddress - the address object
  1253. pConnectionInformation - the remote address
  1254. Options - the send options.
  1255. pMdl - the send buffer
  1256. SendLength - length of data to be sent
  1257. Return Value:
  1258. STATUS_SUCCESS - if the call was successfull.
  1259. Notes:
  1260. In the current implementation the SYNCHRONOUS flag is disregarded for sending
  1261. datagrams because the underlying transports do not block on datagram sends.
  1262. Submission of request and completion of request happen simultaneously.
  1263. If a different behaviour is noted for some transports then the code for
  1264. SendDatagrams need to be implemented along the lines of a send.
  1265. --*/
  1266. {
  1267. NTSTATUS Status = STATUS_SUCCESS;
  1268. PMDL pPartialMdl = NULL;
  1269. ULONG MdlByteCount = MmGetMdlByteCount(pMdl);
  1270. PVOID pMdlAddress = MmGetMdlVirtualAddress(pMdl);
  1271. ULONG TdiOptions = (~RXCE_FLAGS_MASK & Options);
  1272. RxProfile(RxTdi,RxTdiSendDatagram);
  1273. ASSERT(pMdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_SOURCE_IS_NONPAGED_POOL|MDL_PARTIAL));
  1274. DbgDumpTransportAddress(
  1275. L"RxTdiSendDatagram",
  1276. pTransport,
  1277. (PTRANSPORT_ADDRESS)(pConnectionInformation->RemoteAddress)
  1278. );
  1279. if (Options & RXCE_SEND_PARTIAL) {
  1280. if (MdlByteCount > SendLength) {
  1281. pPartialMdl = IoAllocateMdl(pMdlAddress,SendLength,FALSE,FALSE,NULL);
  1282. if (pPartialMdl == NULL) {
  1283. Status = STATUS_INSUFFICIENT_RESOURCES;
  1284. } else {
  1285. RxBuildPartialHeaderMdl(pMdl,pPartialMdl,pMdlAddress,SendLength);
  1286. }
  1287. } else if (MdlByteCount == SendLength) {
  1288. // No need to build a partial MDL, reuse the MDl
  1289. pPartialMdl = pMdl;
  1290. } else {
  1291. RxDbgTrace(0, Dbg,("Mdl Length - %lx Send Length %lx\n",MdlByteCount,SendLength));
  1292. ASSERT(!"MdlByteCount > SendLength");
  1293. Status = STATUS_INVALID_PARAMETER;
  1294. }
  1295. } else {
  1296. pPartialMdl = pMdl;
  1297. }
  1298. if (NT_SUCCESS(Status)) {
  1299. PIRP pIrp;
  1300. pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
  1301. if (pIrp != NULL) {
  1302. // Build the disconnect request to the underlying transport driver
  1303. TdiBuildSendDatagram(
  1304. pIrp, // the IRP
  1305. pTransport->pDeviceObject, // the device object
  1306. pAddress->pFileObject, // the connection (VC) file object
  1307. NULL, // Completion routine
  1308. NULL, // completion context
  1309. pPartialMdl, // the send data buffer
  1310. SendLength, // the send data buffer length
  1311. pConnectionInformation); // remote address information
  1312. Status = RxCeSubmitTdiRequest(
  1313. pTransport->pDeviceObject,
  1314. pIrp);
  1315. } else {
  1316. Status = STATUS_INSUFFICIENT_RESOURCES;
  1317. }
  1318. if ((pAddress->pHandler != NULL) &&
  1319. (pAddress->pHandler->RxCeSendCompleteEventHandler != NULL)) {
  1320. (pAddress->pHandler->RxCeSendCompleteEventHandler)(
  1321. pAddress->pContext,
  1322. pCompletionContext,
  1323. Status);
  1324. }
  1325. if (pIrp != NULL) {
  1326. RxCeFreeIrp(pIrp);
  1327. }
  1328. if ((pPartialMdl != pMdl) && (pPartialMdl != NULL)) {
  1329. IoFreeMdl( pPartialMdl );
  1330. }
  1331. }
  1332. return Status;
  1333. }
  1334. NTSTATUS
  1335. RxTdiRequestCompletion(
  1336. IN PDEVICE_OBJECT DeviceObject,
  1337. IN PIRP Irp,
  1338. IN PVOID Context
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This routine does not complete the Irp. It is used to signal to a
  1343. synchronous part of the driver that it can proceed.
  1344. Arguments:
  1345. DeviceObject - unused.
  1346. Irp - Supplies Irp that the transport has finished processing.
  1347. Context - Supplies the event associated with the Irp.
  1348. Return Value:
  1349. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  1350. processing Irp stack locations at this point.
  1351. --*/
  1352. {
  1353. RxDbgTrace(0, Dbg, ("CompletionEvent\n"));
  1354. if (Context != NULL)
  1355. KeSetEvent((PKEVENT )Context, 0, FALSE);
  1356. return STATUS_MORE_PROCESSING_REQUIRED;
  1357. UNREFERENCED_PARAMETER( DeviceObject );
  1358. UNREFERENCED_PARAMETER( Irp );
  1359. }
  1360. NTSTATUS
  1361. RxCeSubmitTdiRequest (
  1362. IN PDEVICE_OBJECT pDeviceObject,
  1363. IN PIRP pIrp
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. This routine submits a request to TDI and waits for it to complete.
  1368. Arguments:
  1369. IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request
  1370. IN PIRP Irp - TDI request to submit.
  1371. Return Value:
  1372. NTSTATUS - Final status of request.
  1373. --*/
  1374. {
  1375. NTSTATUS Status;
  1376. KEVENT Event;
  1377. KeInitializeEvent (
  1378. &Event,
  1379. NotificationEvent,
  1380. FALSE);
  1381. IoSetCompletionRoutine(
  1382. pIrp, // The IRP
  1383. RxTdiRequestCompletion, // The completion routine
  1384. &Event, // The completion context
  1385. TRUE, // Invoke On Success
  1386. TRUE, // Invoke On Error
  1387. TRUE); // Invoke On Cancel
  1388. //
  1389. // Submit the request
  1390. //
  1391. RxDbgTrace(0, Dbg,("IoCallDriver(pDeviceObject = %lx)\n",pDeviceObject));
  1392. Status = IoCallDriver(pDeviceObject, pIrp);
  1393. if (!NT_SUCCESS(Status)) {
  1394. RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx) returned %lx\n",pDeviceObject,Status));
  1395. }
  1396. if ((Status == STATUS_PENDING) || (Status == STATUS_SUCCESS)) {
  1397. RxDbgTrace(0, Dbg,("Waiting for Tdi Request Completion ....\n"));
  1398. Status = KeWaitForSingleObject(
  1399. &Event, // Object to wait on.
  1400. Executive, // Reason for waiting
  1401. KernelMode, // Processor mode
  1402. FALSE, // Alertable
  1403. NULL); // Timeout
  1404. if (!NT_SUCCESS(Status)) {
  1405. RxDbgTrace(0, Dbg,("RxTdiSubmitRequest could not wait Wait returned %lx\n",Status));
  1406. return Status;
  1407. }
  1408. Status = pIrp->IoStatus.Status;
  1409. } else {
  1410. if (!KeReadStateEvent(&Event)) {
  1411. DbgBreakPoint();
  1412. }
  1413. }
  1414. RxDbgTrace(0, Dbg, ("RxCeSubmitTdiRequest returned %lx\n",Status));
  1415. return Status;
  1416. }
  1417. NTSTATUS
  1418. RxTdiAsynchronousRequestCompletion(
  1419. IN PDEVICE_OBJECT DeviceObject,
  1420. IN PIRP pIrp,
  1421. IN PVOID Context
  1422. )
  1423. /*++
  1424. Routine Description:
  1425. This routine completes an asynchronous send request.
  1426. Arguments:
  1427. DeviceObject - unused.
  1428. Irp - Supplies Irp that the transport has finished processing.
  1429. Context - Supplies the event associated with the Irp.
  1430. Return Value:
  1431. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  1432. processing Irp stack locations at this point.
  1433. --*/
  1434. {
  1435. PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext;
  1436. RxDbgTrace(0, Dbg,("RxTdiAsynchronousRequestCompletion\n"));
  1437. pRequestContext = (PRXTDI_REQUEST_COMPLETION_CONTEXT)Context;
  1438. if (pRequestContext->pPartialMdl != NULL) {
  1439. // Free the partial MDL.
  1440. IoFreeMdl(pRequestContext->pPartialMdl);
  1441. }
  1442. // Invoke the Completion event handler if any.
  1443. if (pRequestContext->pVc == NULL) {
  1444. if (pRequestContext->SendCompletionHandler != NULL) {
  1445. (pRequestContext->SendCompletionHandler)(
  1446. pRequestContext->pEventContext,
  1447. pRequestContext->pCompletionContext,
  1448. pIrp->IoStatus.Status);
  1449. }
  1450. } else {
  1451. if (pRequestContext->ConnectionSendCompletionHandler != NULL) {
  1452. (pRequestContext->ConnectionSendCompletionHandler)(
  1453. pRequestContext->pEventContext,
  1454. pRequestContext->pVc,
  1455. pRequestContext->pCompletionContext,
  1456. pIrp->IoStatus.Status);
  1457. }
  1458. }
  1459. // Free the IRP.
  1460. RxCeFreeIrp(pIrp);
  1461. // Free the request context
  1462. RxFreePool(pRequestContext);
  1463. return STATUS_MORE_PROCESSING_REQUIRED;
  1464. UNREFERENCED_PARAMETER( DeviceObject );
  1465. }
  1466. NTSTATUS
  1467. RxCeSubmitAsynchronousTdiRequest (
  1468. IN PDEVICE_OBJECT pDeviceObject,
  1469. IN PIRP pIrp,
  1470. IN PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. This routine submits a request to TDI and waits for it to complete.
  1475. Arguments:
  1476. IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request
  1477. IN PIRP Irp - TDI request to submit.
  1478. Return Value:
  1479. NTSTATUS - Final status of request.
  1480. --*/
  1481. {
  1482. NTSTATUS Status;
  1483. ASSERT(pRequestContext != NULL);
  1484. IoSetCompletionRoutine(
  1485. pIrp, // The IRP
  1486. RxTdiAsynchronousRequestCompletion, // The completion routine
  1487. pRequestContext, // The completion context
  1488. TRUE, // Invoke On Success
  1489. TRUE, // Invoke On Error
  1490. TRUE); // Invoke On Cancel
  1491. //
  1492. // Submit the request
  1493. //
  1494. RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx)\n",pDeviceObject));
  1495. Status = IoCallDriver(pDeviceObject, pIrp);
  1496. if (!NT_SUCCESS(Status)) {
  1497. RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx) returned %lx\n",pDeviceObject,Status));
  1498. }
  1499. RxDbgTrace(0, Dbg, ("RxCeSubmitAsynchronousTdiRequest returned %lx\n",Status));
  1500. return Status;
  1501. }
  1502. NTSTATUS
  1503. BuildEaBuffer (
  1504. IN ULONG EaNameLength,
  1505. IN PVOID pEaName,
  1506. IN ULONG EaValueLength,
  1507. IN PVOID pEaValue,
  1508. OUT PFILE_FULL_EA_INFORMATION *pEaBufferPointer,
  1509. OUT PULONG pEaBufferLength
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Builds an EA buffer.
  1514. Arguments:
  1515. EaNameLength - Length of the Extended attribute name
  1516. pEaName - the extended attriute name
  1517. EaValueLength - Length of the Extended attribute value
  1518. pEaValue - the extended attribute value
  1519. pBuffer - the buffer for constructing the EA
  1520. --*/
  1521. {
  1522. PFILE_FULL_EA_INFORMATION pEaBuffer;
  1523. ULONG Length;
  1524. RxDbgTrace(0, Dbg, ("BuildEaBuffer\n"));
  1525. // Allocate an EA buffer for passing down the transport address
  1526. *pEaBufferLength = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  1527. EaNameLength + 1 +
  1528. EaValueLength;
  1529. pEaBuffer = (PFILE_FULL_EA_INFORMATION)
  1530. RxAllocatePoolWithTag(
  1531. PagedPool,
  1532. *pEaBufferLength,
  1533. RXCE_TDI_POOLTAG);
  1534. if (pEaBuffer == NULL) {
  1535. return STATUS_INSUFFICIENT_RESOURCES;
  1536. }
  1537. *pEaBufferPointer = pEaBuffer;
  1538. pEaBuffer->NextEntryOffset = 0;
  1539. pEaBuffer->Flags = 0;
  1540. pEaBuffer->EaNameLength = (UCHAR)EaNameLength;
  1541. pEaBuffer->EaValueLength = (USHORT)EaValueLength;
  1542. RtlCopyMemory (
  1543. pEaBuffer->EaName,
  1544. pEaName,
  1545. pEaBuffer->EaNameLength + 1);
  1546. RtlCopyMemory(
  1547. &pEaBuffer->EaName[EaNameLength + 1],
  1548. pEaValue,
  1549. EaValueLength);
  1550. return STATUS_SUCCESS;
  1551. }
  1552. NTSTATUS
  1553. RxTdiCancelConnect(
  1554. IN PRXCE_TRANSPORT pTransport,
  1555. IN PRXCE_ADDRESS pAddress,
  1556. IN PRXCE_CONNECTION pConnection)
  1557. {
  1558. return STATUS_NOT_IMPLEMENTED;
  1559. }
  1560. #if DBG
  1561. void
  1562. DbgDumpTransportAddress(
  1563. PWSTR RoutineName,
  1564. PRXCE_TRANSPORT pTransport,
  1565. PTRANSPORT_ADDRESS pTA
  1566. )
  1567. /*++
  1568. Routine Description:
  1569. Description
  1570. Arguments:
  1571. None
  1572. Return Value:
  1573. None
  1574. --*/
  1575. {
  1576. ULONG i;
  1577. PTA_ADDRESS taa;
  1578. RxDbgTrace(0, Dbg,("%ws on %wZ, address count = %d\n",
  1579. RoutineName, &(pTransport->Name), pTA->TAAddressCount) );
  1580. taa = pTA->Address;
  1581. for( i = 0; i < (ULONG) pTA->TAAddressCount; i++ ){
  1582. RxDbgTrace(0, Dbg, ("\t%d:Address length %d type %d: ",
  1583. i, taa->AddressLength, taa->AddressType ));
  1584. switch (taa->AddressType) {
  1585. case TDI_ADDRESS_TYPE_NETBIOS_EX: {
  1586. PTDI_ADDRESS_NETBIOS_EX address = (PTDI_ADDRESS_NETBIOS_EX) taa->Address;
  1587. RxDbgTrace( 0, Dbg, ("Endpoint: \"%16.16s\" type %d name \"%16.16s\"\n",
  1588. address->EndpointName,
  1589. address->NetbiosAddress.NetbiosNameType,
  1590. address->NetbiosAddress.NetbiosName) );
  1591. break;
  1592. }
  1593. case TDI_ADDRESS_TYPE_NETBIOS: {
  1594. PTDI_ADDRESS_NETBIOS address = (PTDI_ADDRESS_NETBIOS) taa->Address;
  1595. RxDbgTrace( 0, Dbg, ("NBType %d name \"%16.16s\"\n",
  1596. address->NetbiosNameType,
  1597. address->NetbiosName) );
  1598. break;
  1599. }
  1600. case TDI_ADDRESS_TYPE_IP: {
  1601. PTDI_ADDRESS_IP address = (PTDI_ADDRESS_IP) taa->Address;
  1602. RxDbgTrace( 0, Dbg, ("IP port %d addr 0x%x\n", address->sin_port, address->in_addr ) );
  1603. break;
  1604. }
  1605. default: {
  1606. RxDbgTrace( 0, Dbg, ("Unknown!\n") );
  1607. }
  1608. }
  1609. taa = (PTA_ADDRESS) (taa->Address + taa->AddressLength);
  1610. }
  1611. }
  1612. #endif