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.

3164 lines
100 KiB

  1. /****************************************************************************/
  2. // tdtdi.c
  3. //
  4. // Common code for all TDI based Transport Drivers
  5. //
  6. // Copyright (C) 1998-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <ntddk.h>
  9. #include <tdi.h>
  10. #include <tdikrnl.h>
  11. #include "tdtdi.h"
  12. #include <winstaw.h>
  13. #define _DEFCHARINFO_
  14. #include <icadd.h>
  15. #include <ctxdd.h>
  16. #include <sdapi.h>
  17. #include <td.h>
  18. #include <tdi.h>
  19. #define TDTDI_LISTEN_QUEUE_DEPTH 5 // This was hardcoded in afdcom
  20. #ifndef min
  21. #define min(a,b) (((a) < (b)) ? (a) : (b))
  22. #endif
  23. #if DBG
  24. ULONG DbgPrint(PCH Format, ...);
  25. #define DBGPRINT(x) DbgPrint x
  26. #if DBGTRACE
  27. #define DBGENTER(x) DbgPrint x
  28. #define TRACE0(x) DbgPrint x
  29. #define TRACE1(x)
  30. #else
  31. #define DBGENTER(x)
  32. #define TRACE0(x)
  33. #define TRACE1(x)
  34. #endif
  35. #else
  36. #define DBGPRINT(x)
  37. #define DBGENTER(x)
  38. #define TRACE0(x)
  39. #define TRACE1(x)
  40. #endif
  41. /*
  42. DOCUMENT THIS INTERFACE FINALLY!
  43. This is the best I can dig out of these existing interfaces.
  44. Common Sequences:
  45. Startup and Listen - DeviceOpen, DeviceCreateEndpoint, DeviceConnectionWait
  46. DeviceConnectionWait returns an internal handle to represent the connection
  47. it has listened for, accepted, and returned. This handle is useless for any
  48. operations, and is only good for feeding to DeviceOpenEndpoint to get
  49. an endpoint that can be used for communications.
  50. Connect - DeviceOpen, DeviceOpenEndpoint
  51. A DeviceOpen is done to create a new endpoint, then its handle
  52. from DeviceConnectionWait is "inserted" into the empty endpoint.
  53. We now have a real, live connection
  54. Disconnect From Client - DeviceCancelIo
  55. Disconnect From disconn command - DeviceCloseEndpoint?, DeviceCancelIo?
  56. Reconnect - DeviceCancelIo, DeviceClose, DeviceOpen, DeviceOpenEndpoint
  57. Once the user has fully logged onto a new connected WinStation, a
  58. DeviceCancelIo and then a DeviceClose is issued to release the
  59. new logged on WinStation from the connection. While this connection
  60. remains up, a new DeviceOpen and DeviceOpenEndpoint is done to
  61. connect this connection to the users previously disconnected WinStation.
  62. NTSTATUS DeviceOpen( PTD, PSD_OPEN );
  63. Open and initialize private data structures. Calls the TdiDeviceOpen(), but
  64. this is a no-op.
  65. NTSTATUS DeviceClose( PTD, PSD_CLOSE );
  66. Close the transport driver. If its an address endpoint,
  67. it will destroy it. If its a connection endpoint, it
  68. DOES not destroy it.
  69. If the connection endpoint is destroyed, disconnect/reconnect
  70. will be broken.
  71. Calls TdiDeviceClose(), which is another no-op.
  72. NTSTATUS DeviceCreateEndpoint( PTD, PICA_STACK_ADDRESS, PICA_STACK_ADDRESS );
  73. Creates and Address endpoint that can be used for listening.
  74. This does not create any connection endpoints.
  75. NTSTATUS DeviceOpenEndpoint( PTD, PVOID, ULONG );
  76. Takes an existing connection endpoint handle, and makes
  77. an "endpoint" out of it.
  78. This is used by disconnect/reconnect.
  79. NTSTATUS DeviceCloseEndpoint( PTD );
  80. This closes the endpoint.
  81. If its a connection endpoint, it is destroyed.
  82. NTSTATUS DeviceConnectionWait( PTD, PVOID, ULONG, PULONG );
  83. This waits for connections to come in, and returns connected
  84. endpoints in the pIcaEndpoint structure.
  85. NTSTATUS DeviceCancelIo( PTD );
  86. This asks for all I/O on the given endpoint to be canceled.
  87. With TDI, we can not actually cancel I/O, but must hold IRP's
  88. until indication handlers tell us to submit. This is because canceling
  89. I/O on a TDI connection causes the TDI provider to kill the connection.
  90. NTSTATUS DeviceConnectionSend( PTD );
  91. This names sounds like send TD specific data to the host.
  92. This does not actually send anything, but fills in
  93. a structure for the upper level who may actually send it
  94. at some time.
  95. NTSTATUS DeviceConnectionRequest( PTD, PICA_STACK_ADDRESS, PVOID, ULONG, PULONG );
  96. This is used by shadow to act as a network client and
  97. initiate a connection. This is obsolete and not used since
  98. a named pipe TD will handle all shadow traffic.
  99. NTSTATUS DeviceIoctl( PTD, PSD_IOCTL );
  100. NTSTATUS DeviceInitializeRead( PTD, PINBUF );
  101. NTSTATUS DeviceWaitForRead( PTD );
  102. NTSTATUS DeviceReadComplete( PTD, PUCHAR, PULONG );
  103. NTSTATUS DeviceInitializeWrite( PTD, POUTBUF );
  104. NTSTATUS DeviceWaitForStatus( PTD );
  105. NTSTATUS DeviceSetParams( PTD );
  106. NTSTATUS DeviceGetLastError( PTD, PICA_STACK_LAST_ERROR );
  107. NTSTATUS DeviceSubmitRead( PTD, PINBUF );
  108. */
  109. /*
  110. * Context used for connect accept
  111. */
  112. typedef struct _ACCEPT_CONTEXT {
  113. PTD_ENDPOINT pAddressEndpoint;
  114. PTD_ENDPOINT pConnectionEndpoint;
  115. TDI_CONNECTION_INFORMATION RequestInfo;
  116. TDI_CONNECTION_INFORMATION ReturnInfo;
  117. } ACCEPT_CONTEXT, *PACCEPT_CONTEXT;
  118. /*=============================================================================
  119. == External Functions Defined
  120. =============================================================================*/
  121. // These are the functions our TD supplies to ICADD
  122. NTSTATUS DeviceOpen( PTD, PSD_OPEN );
  123. NTSTATUS DeviceClose( PTD, PSD_CLOSE );
  124. NTSTATUS DeviceCreateEndpoint( PTD, PICA_STACK_ADDRESS, PICA_STACK_ADDRESS );
  125. NTSTATUS DeviceOpenEndpoint( PTD, PVOID, ULONG );
  126. NTSTATUS DeviceCloseEndpoint( PTD );
  127. NTSTATUS DeviceConnectionWait( PTD, PVOID, ULONG, PULONG );
  128. NTSTATUS DeviceConnectionSend( PTD );
  129. NTSTATUS DeviceConnectionRequest( PTD, PICA_STACK_ADDRESS, PVOID, ULONG, PULONG );
  130. NTSTATUS DeviceIoctl( PTD, PSD_IOCTL );
  131. NTSTATUS DeviceInitializeRead( PTD, PINBUF );
  132. NTSTATUS DeviceWaitForRead( PTD );
  133. NTSTATUS DeviceReadComplete( PTD, PUCHAR, PULONG );
  134. NTSTATUS DeviceInitializeWrite( PTD, POUTBUF );
  135. NTSTATUS DeviceWaitForStatus( PTD );
  136. NTSTATUS DeviceCancelIo( PTD );
  137. NTSTATUS DeviceSetParams( PTD );
  138. NTSTATUS DeviceGetLastError( PTD, PICA_STACK_LAST_ERROR );
  139. NTSTATUS DeviceSubmitRead( PTD, PINBUF );
  140. NTSTATUS DeviceQueryRemoteAddress( PTD, PVOID, ULONG, PVOID, ULONG, PULONG );
  141. /*=============================================================================
  142. == External Functions Referenced
  143. =============================================================================*/
  144. // These functions are provided by the protocol specific TD module
  145. NTSTATUS TdiDeviceOpen( PTD, PSD_OPEN );
  146. NTSTATUS TdiDeviceClose( PTD, PSD_CLOSE );
  147. NTSTATUS TdiDeviceOpenEndpoint( PTD, PVOID, ULONG );
  148. NTSTATUS TdiDeviceBuildTransportNameAndAddress( PTD, PICA_STACK_ADDRESS,
  149. PUNICODE_STRING,
  150. PTRANSPORT_ADDRESS *, PULONG );
  151. NTSTATUS TdiDeviceBuildWildcardAddress( PTD, PTRANSPORT_ADDRESS *, PULONG );
  152. NTSTATUS TdiDeviceWaitForDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT,
  153. PTRANSPORT_ADDRESS *, PULONG );
  154. NTSTATUS TdiDeviceCompleteDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT, PTRANSPORT_ADDRESS, ULONG );
  155. NTSTATUS TdiDeviceConnectionSend( PTD );
  156. NTSTATUS TdiDeviceReadComplete( PTD, PUCHAR, PULONG );
  157. // These are functions in our support libraries
  158. NTSTATUS MemoryAllocate( ULONG, PVOID * );
  159. VOID MemoryFree( PVOID );
  160. // Tdilib functions
  161. PIRP
  162. _TdiAllocateIrp(
  163. IN PFILE_OBJECT FileObject,
  164. IN PDEVICE_OBJECT DeviceObject OPTIONAL
  165. );
  166. NTSTATUS
  167. _TdiCreateAddress (
  168. IN PUNICODE_STRING pTransportName,
  169. IN PVOID TdiAddress,
  170. IN ULONG TdiAddressLength,
  171. OUT PHANDLE pHandle,
  172. OUT PFILE_OBJECT *ppFileObject,
  173. OUT PDEVICE_OBJECT *ppDeviceObject
  174. );
  175. NTSTATUS
  176. _TdiOpenConnection (
  177. IN PUNICODE_STRING pTransportName,
  178. IN PVOID ConnectionContext,
  179. OUT PHANDLE pHandle,
  180. OUT PFILE_OBJECT *ppFileObject,
  181. OUT PDEVICE_OBJECT *ppDeviceObject
  182. );
  183. NTSTATUS
  184. _TdiListen(
  185. IN PTD pTd,
  186. IN PIRP Irp OPTIONAL,
  187. IN PFILE_OBJECT ConnectionFileObject,
  188. IN PDEVICE_OBJECT ConnectionDeviceObject
  189. );
  190. NTSTATUS
  191. _TdiConnect(
  192. IN PTD pTd,
  193. IN PIRP Irp OPTIONAL,
  194. IN PLARGE_INTEGER pTimeout OPTIONAL,
  195. IN PFILE_OBJECT ConnectionFileObject,
  196. IN PDEVICE_OBJECT ConnectionDeviceObject,
  197. IN ULONG RemoteTransportAddressLength,
  198. IN PTRANSPORT_ADDRESS pRemoteTransportAddress
  199. );
  200. NTSTATUS
  201. _TdiAssociateAddress(
  202. IN PTD pTd,
  203. IN PIRP Irp OPTIONAL,
  204. IN PFILE_OBJECT ConnectionFileObject,
  205. IN HANDLE AddressHandle,
  206. IN PDEVICE_OBJECT AddressDeviceObject
  207. );
  208. NTSTATUS
  209. _TdiDisconnect(
  210. IN PTD pTd,
  211. IN PFILE_OBJECT ConnectionFileObject,
  212. IN PDEVICE_OBJECT ConnectionDeviceObject
  213. );
  214. NTSTATUS
  215. _TdiSetEventHandler (
  216. IN PTD pTd,
  217. IN PDEVICE_OBJECT DeviceObject,
  218. IN PFILE_OBJECT FileObject,
  219. IN ULONG EventType,
  220. IN PVOID EventHandler,
  221. IN PVOID EventContext
  222. );
  223. NTSTATUS
  224. _TdiQueryAddressInfo(
  225. IN PTD pTd,
  226. IN PIRP Irp OPTIONAL,
  227. IN PFILE_OBJECT FileObject,
  228. IN PDEVICE_OBJECT DeviceObject,
  229. IN PTDI_ADDRESS_INFO pAddressInfo,
  230. IN ULONG AddressInfoLength
  231. );
  232. NTSTATUS
  233. _TdCancelReceiveQueue(
  234. PTD pTd,
  235. PTD_ENDPOINT pEndpoint,
  236. NTSTATUS CancelStatus
  237. );
  238. /*=============================================================================
  239. == Internal Functions Defined
  240. =============================================================================*/
  241. NTSTATUS _TdCreateEndpointStruct( PTD, PUNICODE_STRING, PTD_ENDPOINT *, PTRANSPORT_ADDRESS, ULONG );
  242. NTSTATUS _TdCloseEndpoint( PTD, PTD_ENDPOINT );
  243. NTSTATUS
  244. _TdConnectHandler(
  245. IN PVOID TdiEventContext,
  246. IN int RemoteAddressLength,
  247. IN PVOID RemoteAddress,
  248. IN int UserDataLength,
  249. IN PVOID UserData,
  250. IN int OptionsLength,
  251. IN PVOID Options,
  252. OUT CONNECTION_CONTEXT *ConnectionContext,
  253. OUT PIRP *AcceptIrp
  254. );
  255. NTSTATUS
  256. _TdDisconnectHandler (
  257. IN PVOID TdiEventContext,
  258. IN CONNECTION_CONTEXT ConnectionContext,
  259. IN int DisconnectDataLength,
  260. IN PVOID DisconnectData,
  261. IN int DisconnectInformationLength,
  262. IN PVOID DisconnectInformation,
  263. IN ULONG DisconnectFlags
  264. );
  265. NTSTATUS
  266. _TdReceiveHandler (
  267. IN PVOID TdiEventContext,
  268. IN CONNECTION_CONTEXT ConnectionContext,
  269. IN ULONG ReceiveFlags,
  270. IN ULONG BytesIndicated,
  271. IN ULONG BytesAvailable,
  272. OUT ULONG *BytesTaken,
  273. IN PVOID Tsdu,
  274. OUT PIRP *IoRequestPacket
  275. );
  276. NTSTATUS
  277. _TdAcceptComplete (
  278. IN PDEVICE_OBJECT DeviceObject,
  279. IN PIRP Irp,
  280. IN PVOID Context
  281. );
  282. NTSTATUS
  283. _TdCreateConnectionObject(
  284. IN PTD pTd,
  285. IN PUNICODE_STRING pTransportName,
  286. OUT PTD_ENDPOINT *ppEndpoint,
  287. IN PTRANSPORT_ADDRESS pTransportAddress,
  288. IN ULONG TransportAddressLength
  289. );
  290. NTSTATUS
  291. _TdWaitForDatagramConnection(
  292. IN PTD pTd,
  293. IN PTD_ENDPOINT pAddressEndpoint,
  294. OUT PTD_ENDPOINT *ppConnectionEndpoint
  295. );
  296. /*
  297. * Global Data
  298. */
  299. extern USHORT TdiDeviceEndpointType; // Datagram or stream set by TD
  300. extern USHORT TdiDeviceAddressType; // TDI address format by TD
  301. extern USHORT TdiDeviceInBufHeader; // Bytes of header set by TD (0 for stream)
  302. /*******************************************************************************
  303. * DeviceOpen
  304. *
  305. * Allocate and initialize private data structures
  306. *
  307. * pTd (input)
  308. * Pointer to TD data structure
  309. * pSdOpen (input/output)
  310. * Points to the parameter structure SD_OPEN.
  311. ******************************************************************************/
  312. NTSTATUS DeviceOpen(PTD pTd, PSD_OPEN pSdOpen)
  313. {
  314. PTDTDI pTdTdi;
  315. NTSTATUS Status;
  316. DBGENTER(("DeviceOpen: PTD 0x%x\n",pTd));
  317. /*
  318. * Set protocol driver class
  319. */
  320. pTd->SdClass = SdNetwork;
  321. pTd->InBufHeader = TdiDeviceInBufHeader; // For packet oriented protocols
  322. /*
  323. * Return size of header and trailer
  324. */
  325. pSdOpen->SdOutBufHeader = 0;
  326. pSdOpen->SdOutBufTrailer = 0;
  327. /*
  328. * Allocate TDI TD data structure
  329. */
  330. Status = MemoryAllocate( sizeof(*pTdTdi), &pTdTdi );
  331. if ( !NT_SUCCESS(Status) )
  332. goto badalloc;
  333. ASSERT( pTd->pAfd == NULL );
  334. pTd->pAfd = pTdTdi;
  335. /*
  336. * Initialize TDTDI data structure
  337. */
  338. RtlZeroMemory( pTdTdi, sizeof(*pTdTdi) );
  339. /*
  340. * Some protocols will make decisions on lower level
  341. * flow control depending on this value.
  342. */
  343. pTdTdi->OutBufDelay = pSdOpen->PdConfig.Create.OutBufDelay;
  344. /*
  345. * Open device
  346. */
  347. Status = TdiDeviceOpen( pTd, pSdOpen );
  348. if ( !NT_SUCCESS(Status) )
  349. goto badopen;
  350. TRACE0(("DeviceOpen: Context 0x%x\n",pTd->pAfd));
  351. return STATUS_SUCCESS;
  352. /*=============================================================================
  353. == Error returns
  354. =============================================================================*/
  355. /*
  356. * open failed
  357. */
  358. badopen:
  359. MemoryFree( pTd->pAfd );
  360. pTd->pAfd = NULL;
  361. /*
  362. * allocate failed
  363. */
  364. badalloc:
  365. return Status;
  366. }
  367. /*******************************************************************************
  368. * DeviceClose
  369. *
  370. * Close transport driver
  371. * NOTE: this must not close the current connection endpoint
  372. *
  373. * pTd (input)
  374. * Pointer to TD data structure
  375. * pSdClose (input/output)
  376. * Points to the parameter structure SD_CLOSE.
  377. ******************************************************************************/
  378. NTSTATUS DeviceClose(PTD pTd, PSD_CLOSE pSdClose)
  379. {
  380. PTDTDI pTdTdi;
  381. PTD_ENDPOINT pEndpoint;
  382. DBGENTER(("DeviceClose: PTD 0x%x Context 0x%x\n",pTd,pTd->pAfd));
  383. /*
  384. * Get pointer to TDI parameters
  385. */
  386. pTdTdi = (PTDTDI) pTd->pAfd;
  387. /*
  388. * Close address endpoint if we have one
  389. */
  390. if (pTdTdi != NULL) {
  391. if ( pEndpoint = pTdTdi->pAddressEndpoint ) {
  392. TRACE0(("DeviceClose: Closing AddressEndpoint 0x%x\n",pTdTdi->pAddressEndpoint));
  393. pTdTdi->pAddressEndpoint = NULL;
  394. _TdCloseEndpoint( pTd, pEndpoint );
  395. }
  396. #if DBG
  397. if( pEndpoint = pTdTdi->pConnectionEndpoint ) {
  398. ASSERT( IsListEmpty( &pEndpoint->ReceiveQueue) );
  399. TRACE0(("DeviceClose: Connection Endpoint 0x%x idled\n",pEndpoint));
  400. }
  401. #endif
  402. }
  403. /*
  404. * Close device
  405. */
  406. (void)TdiDeviceClose(pTd, pSdClose);
  407. // TdUnload in td\common will free pTd->pAfd
  408. return STATUS_SUCCESS;
  409. }
  410. /*******************************************************************************
  411. * DeviceCreateEndpoint
  412. *
  413. * Create a TDI address object. Do not wait for, or make any connections.
  414. *
  415. * pTd (input)
  416. * Pointer to TD data structure
  417. * pLocalAddress (input)
  418. * Pointer to local address (or null)
  419. * pReturnedAddress (input)
  420. * Pointer to location to save returned (created) address (or null)
  421. ******************************************************************************/
  422. NTSTATUS DeviceCreateEndpoint(
  423. PTD pTd,
  424. PICA_STACK_ADDRESS pLocalAddress,
  425. PICA_STACK_ADDRESS pReturnedAddress)
  426. {
  427. PTDTDI pTdTdi;
  428. NTSTATUS Status;
  429. UNICODE_STRING TransportName;
  430. ULONG TransportAddressLength;
  431. PTD_ENDPOINT pEndpoint = NULL;
  432. PTRANSPORT_ADDRESS pTransportAddress = NULL;
  433. DBGENTER(("DeviceCreateEndpoint: PTD 0x%x\n",pTd));
  434. /*
  435. * Get pointer to TDI parameters
  436. */
  437. pTdTdi = (PTDTDI) pTd->pAfd;
  438. /*
  439. * Build transport device name and address. This is in the TD.
  440. */
  441. Status = TdiDeviceBuildTransportNameAndAddress( pTd, pLocalAddress,
  442. &TransportName,
  443. &pTransportAddress,
  444. &TransportAddressLength );
  445. if ( !NT_SUCCESS( Status ) ) {
  446. DBGPRINT(("DeviceCreateEndpoint: Error building address 0x%x\n",Status));
  447. goto badaddress;
  448. }
  449. /*
  450. * Create the Endpoint structure.
  451. */
  452. Status = _TdCreateEndpointStruct(
  453. pTd,
  454. &TransportName,
  455. &pEndpoint,
  456. pTransportAddress,
  457. TransportAddressLength
  458. );
  459. if ( !NT_SUCCESS( Status ) ) {
  460. DBGPRINT(("DeviceCreateEndpoint: Error creating endpointstruct 0x%x\n",Status));
  461. goto badcreate;
  462. }
  463. pEndpoint->EndpointType = TdiAddressObject;
  464. pEndpoint->TransportHandleProcess = IoGetCurrentProcess();
  465. /*
  466. * Create the TDI address object.
  467. */
  468. Status = _TdiCreateAddress(
  469. &pEndpoint->TransportName,
  470. pEndpoint->pTransportAddress,
  471. pEndpoint->TransportAddressLength,
  472. &pEndpoint->TransportHandle,
  473. &pEndpoint->pFileObject,
  474. &pEndpoint->pDeviceObject
  475. );
  476. if( !NT_SUCCESS(Status) ) {
  477. DBGPRINT(("DeviceCreateEndpoint: Error creating TDI address object 0x%x\n",Status));
  478. _TdCloseEndpoint( pTd, pEndpoint );
  479. goto badcreate;
  480. }
  481. if ( pReturnedAddress ) {
  482. DBGPRINT(("DeviceCreateEndpoint: Address returned Type 0x%x\n",pTransportAddress->Address[0].AddressType));
  483. RtlCopyMemory( pReturnedAddress,
  484. &pTransportAddress->Address[0].AddressType,
  485. min( sizeof( *pReturnedAddress ),
  486. pEndpoint->TransportAddressLength ) );
  487. }
  488. /*
  489. * Save a pointer to the address endpoint
  490. */
  491. pTdTdi->pAddressEndpoint = pEndpoint;
  492. /*
  493. * Free transport name and address buffers
  494. */
  495. MemoryFree( TransportName.Buffer );
  496. MemoryFree( pTransportAddress );
  497. TRACE0(("DeviceCreateEndPoint: AddressEndpoint 0x%x Created, FO 0x%x DO 0x%x, Handle 0x%x\n",pEndpoint,pEndpoint->pFileObject,pEndpoint->pDeviceObject,pEndpoint->TransportHandle));
  498. return( STATUS_SUCCESS );
  499. /*=============================================================================
  500. == Error returns
  501. =============================================================================*/
  502. badcreate:
  503. if ( TransportName.Buffer )
  504. MemoryFree( TransportName.Buffer );
  505. if ( pTransportAddress )
  506. MemoryFree( pTransportAddress );
  507. badaddress:
  508. return( Status );
  509. }
  510. /*******************************************************************************
  511. * DeviceOpenEndpoint
  512. *
  513. * Causes an existing end point to copy its data into a new one.
  514. * The handle is passed in from TermSrv, and was returned to it at one time
  515. * from DeviceConnectionWait().
  516. * NOTE: TermSrv can call this multiple times with the same handle for
  517. * multiple connects/disconnects.
  518. *
  519. * pTd (input)
  520. * Pointer to TD data structure
  521. * pIcaEndpoint (input)
  522. * Pointer to ICA endpoint structure
  523. * IcaEndpointLength (input)
  524. * length of endpoint data
  525. ******************************************************************************/
  526. NTSTATUS DeviceOpenEndpoint(
  527. PTD pTd,
  528. PVOID pIcaEndpoint,
  529. ULONG IcaEndpointLength)
  530. {
  531. PTDTDI pTdTdi;
  532. PTD_STACK_ENDPOINT pStackEndpoint;
  533. PVOID Handle;
  534. ULONG Length;
  535. NTSTATUS Status;
  536. DBGENTER(("DeviceOpenEndpoint: PTD 0x%x\n",pTd));
  537. /*
  538. * Get pointer to TDI parameters
  539. */
  540. pTdTdi = (PTDTDI) pTd->pAfd;
  541. TRACE(( pTd->pContext, TC_TD, TT_API2,
  542. "TDTDI: DeviceOpenEndpoint, copying existing endpoint\n" ));
  543. if( IcaEndpointLength < sizeof(PVOID) ) {
  544. DBGPRINT(("DeviceOpenEndpoint: IcaEndpointLength to small %d\n",IcaEndpointLength));
  545. Status = STATUS_INVALID_HANDLE;
  546. goto done;
  547. }
  548. /*
  549. * Capture the parameter
  550. */
  551. try {
  552. ProbeForRead( pIcaEndpoint, sizeof(PVOID), 1 );
  553. Handle = (*((PVOID *)pIcaEndpoint));
  554. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  555. Status = GetExceptionCode();
  556. DBGPRINT(("DeviceOpenEndpoint: Exception 0x%x\n",Status));
  557. goto done;
  558. }
  559. TRACE0(("DeviceOpenEndpoint: Fetching Handle 0x%x\n",Handle));
  560. /*
  561. * See if ICADD knows about the handle
  562. */
  563. Status = IcaReturnHandle( Handle, &pStackEndpoint, &Length );
  564. if( !NT_SUCCESS(Status) ) {
  565. DBGPRINT(("DeviceOpenEndpoint: ICADD handle 0x%x no good 0x%x\n",Handle,Status));
  566. Status = STATUS_INVALID_HANDLE;
  567. goto done;
  568. }
  569. if( Length != sizeof(TD_STACK_ENDPOINT) ) {
  570. #if DBG
  571. DBGPRINT(("DeviceOpenEndpoint: Bad TD_STACK_ENDPOINT length %d, sb %d\n",Length,sizeof(TD_STACK_ENDPOINT)));
  572. DbgBreakPoint(); // Internal corruption
  573. #endif
  574. Status = STATUS_INVALID_HANDLE;
  575. goto done;
  576. }
  577. ASSERT( pStackEndpoint->AddressType == TdiDeviceAddressType );
  578. ASSERT( pStackEndpoint->pEndpoint->hIcaHandle == Handle );
  579. /*
  580. * Save endpoint as the current connection endpoint
  581. */
  582. pTdTdi->pConnectionEndpoint = pStackEndpoint->pEndpoint;
  583. ASSERT( IsListEmpty( &pTdTdi->pConnectionEndpoint->ReceiveQueue) );
  584. TRACE0(("DeviceOpenEndpoint: Returned Endpoint 0x%x\n",pStackEndpoint->pEndpoint));
  585. /*
  586. * Save the file/device objects used for I/O in the TD structure
  587. */
  588. pTd->pFileObject = pTdTdi->pConnectionEndpoint->pFileObject;
  589. pTd->pDeviceObject = pTdTdi->pConnectionEndpoint->pDeviceObject;
  590. TRACE0(("DeviceOpenEndpoint: Connection Endpoint 0x%x opened on Context 0x%x\n",pTdTdi->pConnectionEndpoint,pTd->pAfd));
  591. TRACE0(("FO 0x%x, DO 0x%x, Handle 0x%x\n",pTdTdi->pConnectionEndpoint->pFileObject,pTdTdi->pConnectionEndpoint->pDeviceObject,pTdTdi->pConnectionEndpoint->TransportHandle));
  592. Status = STATUS_SUCCESS;
  593. if ( NT_SUCCESS(Status) ) {
  594. Status = TdiDeviceOpenEndpoint( pTd, pIcaEndpoint, IcaEndpointLength );
  595. }
  596. done:
  597. return( Status );
  598. }
  599. /*******************************************************************************
  600. * DeviceCloseEndpoint
  601. ******************************************************************************/
  602. NTSTATUS DeviceCloseEndpoint(PTD pTd)
  603. {
  604. ULONG Length;
  605. KIRQL OldIrql;
  606. PTDTDI pTdTdi;
  607. NTSTATUS Status;
  608. PTD_ENDPOINT pEndpoint;
  609. PTD_STACK_ENDPOINT pStackEndpoint;
  610. DBGENTER(("DeviceCloseEndpoint: PTD 0x%x, Context 0x%x\n",pTd,pTd->pAfd));
  611. /*
  612. * Get pointer to TDI parameters
  613. */
  614. pTdTdi = (PTDTDI) pTd->pAfd;
  615. /*
  616. * Close connection endpoint if we have one
  617. * NOTE: The address endpoint, if there is one,
  618. * gets closed in the DeviceClose routine.
  619. */
  620. if ( pEndpoint = pTdTdi->pConnectionEndpoint ) {
  621. TRACE0(("DeviceCloseEndpoint: Closing Connection Endpoint 0x%x, on Context 0x%x\n",pEndpoint,pTd->pAfd));
  622. ASSERT( pEndpoint->EndpointType != TdiAddressObject );
  623. ExAcquireSpinLock( &pEndpoint->Spinlock, &OldIrql );
  624. pEndpoint->Disconnected = TRUE;
  625. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  626. /*
  627. * Cancel any pended receives
  628. */
  629. _TdCancelReceiveQueue(pTd, pEndpoint, STATUS_LOCAL_DISCONNECT );
  630. pTd->pFileObject = NULL;
  631. pTd->pDeviceObject = NULL;
  632. pTdTdi->pConnectionEndpoint = NULL;
  633. // If a handle registered with ICADD, close it
  634. if( pEndpoint->hIcaHandle ) {
  635. Status = IcaCloseHandle( pEndpoint->hIcaHandle, &pStackEndpoint, &Length );
  636. if( NT_SUCCESS(Status) ) {
  637. ASSERT( pStackEndpoint->pEndpoint == pEndpoint );
  638. /*
  639. * Release our context memory
  640. */
  641. MemoryFree( pStackEndpoint );
  642. }
  643. else {
  644. DBGPRINT(("DeviceCloseEndpoint: hIcaDevice 0x%x Invalid!\n",pEndpoint->hIcaHandle));
  645. #if DBG
  646. DbgBreakPoint();
  647. #endif
  648. }
  649. }
  650. _TdCloseEndpoint( pTd, pEndpoint );
  651. }
  652. return( STATUS_SUCCESS );
  653. }
  654. /*******************************************************************************
  655. * DeviceConnectionWait
  656. *
  657. * This function is called in a loop from the upper level. We must create
  658. * a connection object, associate it with the address object, listen on it,
  659. * and return a single connection to our caller. We are called again for
  660. * more connections.
  661. * NOTE: The endpoint structure is an opaque, variable length data
  662. * structure whose length and contents are determined by the
  663. * transport driver.
  664. *
  665. * ENTRY:
  666. * pTd (input)
  667. * Pointer to TD data structure
  668. * pIcaEndpoint (output)
  669. * Points to a buffer to receive the current endpoint
  670. * Length (input)
  671. * Length of the buffer pointed to by pIcaEndpoint
  672. * BytesReturned (output)
  673. * Points to the actual number of bytes written to pIcaEndpoint
  674. *
  675. * EXIT:
  676. * STATUS_SUCCESS - no error
  677. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  678. ******************************************************************************/
  679. NTSTATUS DeviceConnectionWait(
  680. PTD pTd,
  681. PVOID pIcaEndpoint,
  682. ULONG Length,
  683. PULONG BytesReturned)
  684. {
  685. PTDTDI pTdTdi;
  686. NTSTATUS Status;
  687. KIRQL OldIrql;
  688. PLIST_ENTRY pEntry;
  689. PVOID Handle;
  690. PTD_ENDPOINT pAddressEndpoint;
  691. PTD_ENDPOINT pConnectionEndpoint = NULL;
  692. PTD_STACK_ENDPOINT pStackEndpoint = NULL;
  693. DBGENTER(("DeviceConnectionWait: PTD 0x%x\n",pTd));
  694. /*
  695. * Get pointer to TDI parameters
  696. */
  697. pTdTdi = (PTDTDI) pTd->pAfd;
  698. if (pTd->fClosing) {
  699. return STATUS_DEVICE_NOT_READY;
  700. }
  701. /*
  702. * Initialize return buffer size
  703. */
  704. *BytesReturned = sizeof(TD_STACK_ENDPOINT);
  705. /*
  706. * Verify output endpoint buffer is large enough
  707. */
  708. if ( Length < sizeof(TD_STACK_ENDPOINT) ) {
  709. Status = STATUS_BUFFER_TOO_SMALL;
  710. DBGPRINT(("DeviceConnectionWait: Output buffer to small\n"));
  711. goto done;
  712. }
  713. /*
  714. * Ensure we have a TDI address endpoint already
  715. */
  716. if ( (pAddressEndpoint = pTdTdi->pAddressEndpoint) == NULL ) {
  717. Status = STATUS_DEVICE_NOT_READY;
  718. DBGPRINT(("DeviceConnectionWait: No TDI address object\n"));
  719. goto done;
  720. }
  721. /*
  722. * Different handling for datagram connections
  723. */
  724. if (TdiDeviceEndpointType == TdiConnectionDatagram) {
  725. Status = _TdWaitForDatagramConnection(
  726. pTd,
  727. pAddressEndpoint,
  728. &pConnectionEndpoint);
  729. if (!NT_SUCCESS(Status)) {
  730. DBGPRINT(("DeviceConnectionWait: Error Status 0x%x from "
  731. "_TdWaitForDatagramConnection\n", Status));
  732. return Status;
  733. }
  734. goto ConnectAccepted;
  735. }
  736. ExAcquireSpinLock(&pAddressEndpoint->Spinlock, &OldIrql);
  737. /*
  738. * Data receive indication must be registered on the
  739. * address endpoint before any data endpoints are created.
  740. *
  741. * This is because we can not set receive indication on a
  742. * dataendpoint, it can only be inherited from its
  743. * address endpoint.
  744. */
  745. if (!pAddressEndpoint->RecvIndicationRegistered) {
  746. pAddressEndpoint->RecvIndicationRegistered = TRUE;
  747. ExReleaseSpinLock(&pAddressEndpoint->Spinlock, OldIrql);
  748. /*
  749. * Register the receive event handler
  750. */
  751. Status = _TdiSetEventHandler(
  752. pTd,
  753. pAddressEndpoint->pDeviceObject,
  754. pAddressEndpoint->pFileObject,
  755. TDI_EVENT_RECEIVE,
  756. (PVOID)_TdReceiveHandler,
  757. (PVOID)pAddressEndpoint // Context
  758. );
  759. ASSERT( NT_SUCCESS(Status) );
  760. pAddressEndpoint->DisconnectIndicationRegistered = TRUE;
  761. /*
  762. * Register the disconnect event handler
  763. */
  764. Status = _TdiSetEventHandler(
  765. pTd,
  766. pAddressEndpoint->pDeviceObject,
  767. pAddressEndpoint->pFileObject,
  768. TDI_EVENT_DISCONNECT,
  769. (PVOID)_TdDisconnectHandler,
  770. (PVOID)pAddressEndpoint // Context
  771. );
  772. ASSERT( NT_SUCCESS(Status) );
  773. ExAcquireSpinLock( &pAddressEndpoint->Spinlock, &OldIrql );
  774. }
  775. /*
  776. * Everytime into this function, we attempt to create more
  777. * Connection object's util we have reached TDTDI_LISTEN_QUEUE_DEPTH.
  778. *
  779. * These connection objects are linked off of our address endpoint.
  780. *
  781. * This is because we can only create connection objects
  782. * at call level, not at indication level. The indication level
  783. * will grab connection objects off of the address endpoint,
  784. * and accept them. It will then set the accept event on the
  785. * address object. This is optimized for only (1) thread
  786. * accepting connections, which is the current TD design.
  787. * Otherwise, thundering herd could occur on the accept event.
  788. *
  789. * This function then returns with the accepted connection
  790. * object. The upper level listen thread will then call
  791. * this function again to retrieve another connection.
  792. *
  793. * This prevents the refusing of connections due to not
  794. * having any outstanding listen's available when a WinFrame
  795. * client connect request comes in.
  796. */
  797. while (pAddressEndpoint->ConnectionQueueSize <= TDTDI_LISTEN_QUEUE_DEPTH) {
  798. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  799. Status = _TdCreateConnectionObject(
  800. pTd,
  801. &pAddressEndpoint->TransportName,
  802. &pConnectionEndpoint,
  803. pAddressEndpoint->pTransportAddress,
  804. pAddressEndpoint->TransportAddressLength
  805. );
  806. ExAcquireSpinLock( &pAddressEndpoint->Spinlock, &OldIrql );
  807. if( !NT_SUCCESS(Status) ) {
  808. DBGPRINT(("DeviceConnectionWait: Error 0x%x Creating ConnectionObject\n",Status));
  809. break;
  810. }
  811. ASSERT( pConnectionEndpoint->Connected == FALSE );
  812. InsertTailList( &pAddressEndpoint->ConnectionQueue, &pConnectionEndpoint->ConnectionLink );
  813. pAddressEndpoint->ConnectionQueueSize++;
  814. }
  815. /*
  816. * If we have not registered our Connect Indication handler
  817. * yet, do it now. We had to delay it until connection objects
  818. * were created and ready.
  819. */
  820. if (!pAddressEndpoint->ConnectIndicationRegistered) {
  821. pTdTdi->pAddressEndpoint->ConnectIndicationRegistered = TRUE;
  822. ASSERT( !IsListEmpty( &pAddressEndpoint->ConnectionQueue ) );
  823. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  824. /*
  825. * Register to receive connect indications
  826. *
  827. * *** Note that Connect events can be delivered IMMEDIATELY upon
  828. * completion of this request!
  829. */
  830. Status = _TdiSetEventHandler(
  831. pTd,
  832. pAddressEndpoint->pDeviceObject,
  833. pAddressEndpoint->pFileObject,
  834. TDI_EVENT_CONNECT,
  835. (PVOID)_TdConnectHandler,
  836. (PVOID)pAddressEndpoint // Context
  837. );
  838. if (!NT_SUCCESS(Status)) {
  839. DBGPRINT(("DeviceConnectionWait: Error 0x%x Setting TdiConnectHandler\n",Status));
  840. ExAcquireSpinLock( &pAddressEndpoint->Spinlock, &OldIrql );
  841. pTdTdi->pAddressEndpoint->ConnectIndicationRegistered = FALSE;
  842. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  843. goto done;
  844. }
  845. ExAcquireSpinLock( &pAddressEndpoint->Spinlock, &OldIrql );
  846. }
  847. /*
  848. * While holding the spinlock, see if any connected objects
  849. * are on the connected queue.
  850. */
  851. while (IsListEmpty( &pAddressEndpoint->ConnectedQueue)) {
  852. KeResetEvent( &pAddressEndpoint->AcceptEvent );
  853. ASSERT( pAddressEndpoint->Waiter == FALSE );
  854. pAddressEndpoint->Waiter = TRUE;
  855. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  856. Status = IcaWaitForSingleObject(
  857. pTd->pContext,
  858. &pAddressEndpoint->AcceptEvent,
  859. (-1) // No timeout
  860. );
  861. ExAcquireSpinLock( &pAddressEndpoint->Spinlock, &OldIrql );
  862. ASSERT( pAddressEndpoint->Waiter == TRUE );
  863. pAddressEndpoint->Waiter = FALSE;
  864. /*
  865. * Wait failure, could be due to thread receiving APC.
  866. */
  867. if( Status != STATUS_SUCCESS ) {
  868. DBGPRINT(("DeviceConnectionWait: Thread wait interrupted! Status 0x%x\n",Status));
  869. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  870. return( Status );
  871. }
  872. if( pTd->fClosing ) {
  873. DBGPRINT(("DeviceConnectionWait: TD is Closing!\n"));
  874. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  875. return( STATUS_CTX_CLOSE_PENDING );
  876. }
  877. // Should only be (1) accept thread in the TD.
  878. ASSERT( !IsListEmpty(&pAddressEndpoint->ConnectedQueue) );
  879. }
  880. /*
  881. * Dequeue the connected connection object
  882. */
  883. pEntry = RemoveHeadList( &pAddressEndpoint->ConnectedQueue );
  884. pAddressEndpoint->ConnectionQueueSize--;
  885. pConnectionEndpoint = CONTAINING_RECORD( pEntry, TD_ENDPOINT, ConnectionLink );
  886. ASSERT( pConnectionEndpoint->Connected == TRUE );
  887. /*
  888. * There could have been a final phase accept error, or
  889. * the remote side dropped the connection right away.
  890. *
  891. * In this case, we must tear down the errored connection.
  892. */
  893. if (!NT_SUCCESS(pConnectionEndpoint->Status)) {
  894. Status = pConnectionEndpoint->Status;
  895. DBGPRINT(("DeviceConnectionWait: Accept indication failed, Status 0x%x\n",Status));
  896. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  897. _TdCloseEndpoint( pTd, pConnectionEndpoint );
  898. return( Status );
  899. }
  900. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  901. ConnectAccepted:
  902. /*
  903. * Allocate a context structure and register our endpoint as
  904. * a handle with ICADD. The handle returned by ICADD will then
  905. * be placed into the user mode callers buffer as the endpoint
  906. * handle.
  907. *
  908. * A later call to DeviceOpenEndpoint() will validate this handle,
  909. * retreive the context, and allow use of the endpoint.
  910. */
  911. Status = MemoryAllocate( sizeof(TD_STACK_ENDPOINT), &pStackEndpoint );
  912. if( !NT_SUCCESS(Status) ) {
  913. DBGPRINT(("DeviceConnectionWait: Could not allocate memory 0x%x\n",Status));
  914. _TdCloseEndpoint( pTd, pConnectionEndpoint );
  915. return( Status );
  916. }
  917. pStackEndpoint->AddressType = TdiDeviceAddressType;
  918. pStackEndpoint->pEndpoint = pConnectionEndpoint;
  919. Status = IcaCreateHandle( (PVOID)pStackEndpoint, sizeof(TD_STACK_ENDPOINT), &Handle );
  920. if( !NT_SUCCESS(Status) ) {
  921. DBGPRINT(("DeviceConnectionWait: Error creating ICADD handle 0x%x\n",Status));
  922. MemoryFree( pStackEndpoint );
  923. _TdCloseEndpoint( pTd, pConnectionEndpoint );
  924. return( Status );
  925. }
  926. Status = STATUS_SUCCESS;
  927. /*
  928. * Fill in the stack endpoint structure to be returned
  929. */
  930. try {
  931. ProbeForWrite( pIcaEndpoint, sizeof(PVOID), 1 );
  932. *((PVOID *)pIcaEndpoint) = Handle;
  933. *BytesReturned = sizeof(PVOID);
  934. } except(EXCEPTION_EXECUTE_HANDLER) {
  935. Status = GetExceptionCode();
  936. DBGPRINT(("DeviceConnectionWait: Exception returning result 0x%x\n",Status));
  937. }
  938. // Exception
  939. if( !NT_SUCCESS(Status) ) {
  940. ULONG Length;
  941. NTSTATUS Status2;
  942. DBGPRINT(("DeviceConnectionWait: Exception returning result 0x%x\n",Status));
  943. Status2 = IcaCloseHandle( Handle, &pStackEndpoint, &Length );
  944. if( NT_SUCCESS(Status2) ) {
  945. MemoryFree( pStackEndpoint );
  946. }
  947. _TdCloseEndpoint( pTd, pConnectionEndpoint );
  948. return( Status );
  949. }
  950. pConnectionEndpoint->hIcaHandle = Handle;
  951. TRACE0(("DeviceConnectionWait: New Connection Endpoint 0x%x Returned on Context 0x%x, AddressEndpoint 0x%x\n",pConnectionEndpoint,pTd->pAfd,pAddressEndpoint));
  952. TRACE0(("FO 0x%x, DO 0x%x, Handle 0x%x\n",pConnectionEndpoint->pFileObject,pConnectionEndpoint->pDeviceObject,pConnectionEndpoint->TransportHandle));
  953. done:
  954. return Status;
  955. }
  956. /*******************************************************************************
  957. * DeviceConnectionSend
  958. *
  959. * Initialize host module data structure, which gets sent to the client.
  960. ******************************************************************************/
  961. NTSTATUS DeviceConnectionSend(PTD pTd)
  962. {
  963. return TdiDeviceConnectionSend(pTd);
  964. }
  965. /*******************************************************************************
  966. * DeviceConnectionRequest
  967. *
  968. * Initiate a connection to the specified remote address
  969. *
  970. * ENTRY:
  971. * pTd (input)
  972. * Pointer to TD data structure
  973. * pRemoteAddress (input)
  974. * Pointer to remote address to connect to
  975. * pIcaEndpoint (output)
  976. * Points to a buffer to receive the current endpoint
  977. * Length (input)
  978. * Length of the buffer pointed to by pIcaEndpoint
  979. * BytesReturned (output)
  980. * Pointer to location to return length of pIcaEndpoint
  981. *
  982. * EXIT:
  983. * STATUS_SUCCESS - no error
  984. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  985. ******************************************************************************/
  986. NTSTATUS DeviceConnectionRequest(
  987. PTD pTd,
  988. PICA_STACK_ADDRESS pRemoteAddress,
  989. PVOID pIcaEndpoint,
  990. ULONG Length,
  991. PULONG BytesReturned)
  992. {
  993. PTDTDI pTdTdi;
  994. NTSTATUS Status;
  995. KIRQL OldIrql;
  996. PLIST_ENTRY pEntry;
  997. PVOID Handle;
  998. PTD_ENDPOINT pAddressEndpoint;
  999. PTD_ENDPOINT pConnectionEndpoint = NULL;
  1000. PTD_STACK_ENDPOINT pStackEndpoint = NULL;
  1001. ICA_STACK_ADDRESS LocalAddress;
  1002. PICA_STACK_ADDRESS pLocalAddress = &LocalAddress;
  1003. UNICODE_STRING TransportName;
  1004. ULONG TransportAddressLength;
  1005. PTD_ENDPOINT pEndpoint = NULL;
  1006. PTRANSPORT_ADDRESS pTransportAddress = NULL;
  1007. UNICODE_STRING RemoteTransportName;
  1008. ULONG RemoteTransportAddressLength;
  1009. PTRANSPORT_ADDRESS pRemoteTransportAddress = NULL;
  1010. ULONG timeout;
  1011. LARGE_INTEGER WaitTimeout;
  1012. PLARGE_INTEGER pWaitTimeout = NULL;
  1013. PTDI_ADDRESS_IP pTdiAddress;
  1014. #if DBG
  1015. PTDI_ADDRESS_INFO pTdiLocalAddressInfo;
  1016. ULONG LocalAddressInfoLength;
  1017. #endif
  1018. DBGENTER(("DeviceConnectionRequest: PTD 0x%x\n",pTd));
  1019. //
  1020. // This part is from the above DeviceConnectionwait:
  1021. //
  1022. if (pRemoteAddress == NULL) {
  1023. Status = STATUS_INVALID_PARAMETER;
  1024. goto done;
  1025. }
  1026. /*
  1027. * Get pointer to TDI parameters
  1028. */
  1029. pTdTdi = (PTDTDI) pTd->pAfd;
  1030. if (pTd->fClosing) {
  1031. return STATUS_DEVICE_NOT_READY;
  1032. }
  1033. /*
  1034. * Initialize return buffer size
  1035. */
  1036. *BytesReturned = sizeof(TD_STACK_ENDPOINT);
  1037. /*
  1038. * Verify output endpoint buffer is large enough
  1039. */
  1040. if ( Length < sizeof(TD_STACK_ENDPOINT) ) {
  1041. Status = STATUS_BUFFER_TOO_SMALL;
  1042. DBGPRINT(("DeviceConnectionRequest: Output buffer to small\n"));
  1043. goto done;
  1044. }
  1045. /*
  1046. * Different handling for datagram connections
  1047. */
  1048. if (TdiDeviceEndpointType == TdiConnectionDatagram) {
  1049. Status = STATUS_NOT_SUPPORTED;
  1050. goto done;
  1051. }
  1052. //
  1053. // Extract timeout value and reset to NULL, will require adding timeout
  1054. // into ICA_STACK_ADDRESS, too riskly for Whistler.
  1055. //
  1056. pTdiAddress = (PTDI_ADDRESS_IP) ((PCHAR)pRemoteAddress + 2);
  1057. RtlCopyMemory( &timeout, &pTdiAddress->sin_zero[0], sizeof(timeout) );
  1058. RtlZeroMemory( &pTdiAddress->sin_zero[0], sizeof(timeout) );
  1059. //
  1060. // Build the remote address
  1061. //
  1062. DBGPRINT(("TDTCP:DeviceConnectionRequest: building REMOTE address ...\n"));
  1063. DBGPRINT(("TDTCP:DeviceConnectionRequest: Timeout %d\n", timeout));
  1064. Status = TdiDeviceBuildTransportNameAndAddress( pTd, pRemoteAddress,
  1065. &RemoteTransportName,
  1066. &pRemoteTransportAddress,
  1067. &RemoteTransportAddressLength );
  1068. if ( !NT_SUCCESS( Status ) ) {
  1069. DBGPRINT(("DeviceConnectionRequest: Error building address 0x%x\n",Status));
  1070. goto badaddress;
  1071. }
  1072. MemoryFree( RemoteTransportName.Buffer ); // not used, should make it optional in the call above
  1073. RemoteTransportName.Buffer = NULL;
  1074. /*
  1075. * Build transport device name and address. This is in the TD.
  1076. */
  1077. DBGPRINT(("TDTCP:DeviceConnectionRequest: building LOCAL address ...\n"));
  1078. //
  1079. // We build a wild card local address let tcpip driver pick up port and NIC card.
  1080. //
  1081. RtlZeroMemory(pLocalAddress, sizeof(LocalAddress));
  1082. *(PUSHORT)pLocalAddress = TDI_ADDRESS_TYPE_IP;
  1083. Status = TdiDeviceBuildTransportNameAndAddress( pTd, pLocalAddress,
  1084. &TransportName,
  1085. &pTransportAddress,
  1086. &TransportAddressLength );
  1087. if ( !NT_SUCCESS( Status ) ) {
  1088. DBGPRINT(("DeviceConnectionRequest: Error building address 0x%x\n",Status));
  1089. goto badaddress;
  1090. }
  1091. /*
  1092. * Create the Endpoint structure.
  1093. */
  1094. Status = _TdCreateEndpointStruct(
  1095. pTd,
  1096. &TransportName,
  1097. &pEndpoint,
  1098. pTransportAddress,
  1099. TransportAddressLength
  1100. );
  1101. if ( !NT_SUCCESS( Status ) ) {
  1102. DBGPRINT(("DeviceConnectionRequest: Error creating endpointstruct 0x%x\n",Status));
  1103. goto badcreate;
  1104. }
  1105. pEndpoint->EndpointType = TdiAddressObject;
  1106. pEndpoint->TransportHandleProcess = IoGetCurrentProcess();
  1107. /*
  1108. * Create the TDI address object.
  1109. */
  1110. Status = _TdiCreateAddress(
  1111. &pEndpoint->TransportName,
  1112. pEndpoint->pTransportAddress,
  1113. pEndpoint->TransportAddressLength,
  1114. &pEndpoint->TransportHandle,
  1115. &pEndpoint->pFileObject,
  1116. &pEndpoint->pDeviceObject
  1117. );
  1118. if( !NT_SUCCESS(Status) ) {
  1119. DBGPRINT(("DeviceConnectionRequest: Error creating TDI address object 0x%x\n",Status));
  1120. _TdCloseEndpoint( pTd, pEndpoint );
  1121. goto badcreate;
  1122. }
  1123. /*
  1124. * Save a pointer to the address endpoint
  1125. */
  1126. pTdTdi->pAddressEndpoint = pEndpoint;
  1127. pAddressEndpoint = pTdTdi->pAddressEndpoint;
  1128. /*
  1129. * Free transport name and address buffers
  1130. */
  1131. MemoryFree( TransportName.Buffer );
  1132. TransportName.Buffer = NULL;
  1133. MemoryFree( pTransportAddress );
  1134. pTransportAddress = NULL;
  1135. //*************************************************************
  1136. ExAcquireSpinLock(&pAddressEndpoint->Spinlock, &OldIrql);
  1137. /*
  1138. * Data receive indication must be registered on the
  1139. * address endpoint before any data endpoints are created.
  1140. *
  1141. * This is because we can not set receive indication on a
  1142. * dataendpoint, it can only be inherited from its
  1143. * address endpoint.
  1144. */
  1145. if (!pAddressEndpoint->RecvIndicationRegistered) {
  1146. pAddressEndpoint->RecvIndicationRegistered = TRUE;
  1147. ExReleaseSpinLock(&pAddressEndpoint->Spinlock, OldIrql);
  1148. /*
  1149. * Register the receive event handler
  1150. */
  1151. Status = _TdiSetEventHandler(
  1152. pTd,
  1153. pAddressEndpoint->pDeviceObject,
  1154. pAddressEndpoint->pFileObject,
  1155. TDI_EVENT_RECEIVE,
  1156. (PVOID)_TdReceiveHandler,
  1157. (PVOID)pAddressEndpoint // Context
  1158. );
  1159. ASSERT( NT_SUCCESS(Status) );
  1160. if( !NT_SUCCESS(Status) )
  1161. {
  1162. // Already released the spin lock
  1163. DBGPRINT(("DeviceConnectionRequest: failed to _TdiSetEventHandler on TDI_EVENT_RECEIVE 0x%x\n",Status));
  1164. goto badconnect1;
  1165. }
  1166. pAddressEndpoint->DisconnectIndicationRegistered = TRUE;
  1167. /*
  1168. * Register the disconnect event handler
  1169. */
  1170. Status = _TdiSetEventHandler(
  1171. pTd,
  1172. pAddressEndpoint->pDeviceObject,
  1173. pAddressEndpoint->pFileObject,
  1174. TDI_EVENT_DISCONNECT,
  1175. (PVOID)_TdDisconnectHandler,
  1176. (PVOID)pAddressEndpoint // Context
  1177. );
  1178. ASSERT( NT_SUCCESS(Status) );
  1179. if( !NT_SUCCESS(Status) )
  1180. {
  1181. // Already released the spin lock
  1182. DBGPRINT(("DeviceConnectionRequest: failed to _TdiSetEventHandler on TDI_EVENT_DISCONNECT 0x%x\n",Status));
  1183. goto badconnect1;
  1184. }
  1185. }
  1186. else {
  1187. ExReleaseSpinLock( &pAddressEndpoint->Spinlock, OldIrql );
  1188. }
  1189. // now create a TDI connection object
  1190. Status = _TdCreateConnectionObject(
  1191. pTd,
  1192. &pAddressEndpoint->TransportName,
  1193. &pConnectionEndpoint,
  1194. pAddressEndpoint->pTransportAddress,
  1195. pAddressEndpoint->TransportAddressLength
  1196. );
  1197. if ( !NT_SUCCESS(Status) ) {
  1198. DBGPRINT(("DeviceConnectionRequest: failed to create ConnectionObject 0x%x\n",Status));
  1199. goto badconnect1;
  1200. }
  1201. if( 0 != timeout ) {
  1202. WaitTimeout = RtlEnlargedIntegerMultiply( timeout * 1000, -10000 );
  1203. pWaitTimeout = &WaitTimeout;
  1204. }
  1205. pTdTdi->pConnectionEndpoint = pConnectionEndpoint;
  1206. Status = _TdiConnect( pTd,
  1207. NULL, // will allocate the IRP internally
  1208. pWaitTimeout,
  1209. pConnectionEndpoint->pFileObject,
  1210. pConnectionEndpoint->pDeviceObject,
  1211. RemoteTransportAddressLength,
  1212. pRemoteTransportAddress
  1213. );
  1214. if ( !NT_SUCCESS(Status) ) {
  1215. DBGPRINT(("DeviceConnectionRequest: failed to connect 0x%x\n",Status));
  1216. goto badconnect;
  1217. }
  1218. //
  1219. // signal accept event, connect logic don't depend on it.
  1220. //
  1221. KeSetEvent( &pAddressEndpoint->AcceptEvent, IO_NETWORK_INCREMENT, FALSE );
  1222. MemoryFree( pRemoteTransportAddress );
  1223. pRemoteTransportAddress = NULL;
  1224. #if DBG
  1225. //
  1226. // Query local address use to connect.
  1227. //
  1228. LocalAddressInfoLength = pAddressEndpoint->TransportAddressLength+4;
  1229. Status = MemoryAllocate( LocalAddressInfoLength, &pTdiLocalAddressInfo );
  1230. if ( NT_SUCCESS( Status ) ) {
  1231. Status = _TdiQueryAddressInfo(
  1232. pTd,
  1233. NULL,
  1234. pConnectionEndpoint->pFileObject,
  1235. pConnectionEndpoint->pDeviceObject,
  1236. pTdiLocalAddressInfo,
  1237. LocalAddressInfoLength
  1238. );
  1239. if( NT_SUCCESS(Status) )
  1240. {
  1241. int i;
  1242. TA_ADDRESS* pTdAddress;
  1243. TDI_ADDRESS_IP* pTdiAddressIp;
  1244. pTdAddress = &pTdiLocalAddressInfo->Address.Address[0];
  1245. DBGPRINT( ("number of local address %d\n", pTdiLocalAddressInfo->Address.TAAddressCount) );
  1246. for( i=0; i < pTdiLocalAddressInfo->Address.TAAddressCount; i++ )
  1247. {
  1248. DBGPRINT( (" Address Type %d\n", pTdAddress->AddressType) );
  1249. if( TDI_ADDRESS_TYPE_IP == pTdAddress->AddressType )
  1250. {
  1251. pTdiAddressIp = (TDI_ADDRESS_IP *)&pTdAddress->Address[0];
  1252. DBGPRINT((" Port %x\n", pTdiAddressIp->sin_port) );
  1253. DBGPRINT((" IP %u.%u.%u.%u\n",
  1254. (pTdiAddressIp->in_addr & 0xff000000) >> 24,
  1255. (pTdiAddressIp->in_addr & 0x00ff0000) >> 16,
  1256. (pTdiAddressIp->in_addr & 0x0000ff00) >> 8,
  1257. (pTdiAddressIp->in_addr & 0x000000ff) ));
  1258. }
  1259. pTdAddress++;
  1260. }
  1261. }
  1262. MemoryFree( pTdiLocalAddressInfo );
  1263. }
  1264. #endif
  1265. //**********************************************************************************
  1266. /*
  1267. * Allocate a context structure and register our endpoint as
  1268. * a handle with ICADD. The handle returned by ICADD will then
  1269. * be placed into the user mode callers buffer as the endpoint
  1270. * handle.
  1271. */
  1272. Status = MemoryAllocate( sizeof(TD_STACK_ENDPOINT), &pStackEndpoint );
  1273. if( !NT_SUCCESS(Status) ) {
  1274. DBGPRINT(("DeviceConnectionRequest: Could not allocate memory 0x%x\n",Status));
  1275. goto badconnect;
  1276. }
  1277. pStackEndpoint->AddressType = TdiDeviceAddressType;
  1278. pStackEndpoint->pEndpoint = pConnectionEndpoint;
  1279. Status = IcaCreateHandle( (PVOID)pStackEndpoint, sizeof(TD_STACK_ENDPOINT), &Handle );
  1280. if( !NT_SUCCESS(Status) ) {
  1281. DBGPRINT(("DeviceConnectionRequest: Error creating ICADD handle 0x%x\n",Status));
  1282. MemoryFree( pStackEndpoint );
  1283. goto badconnect;
  1284. }
  1285. Status = STATUS_SUCCESS;
  1286. /*
  1287. * Fill in the stack endpoint structure to be returned
  1288. */
  1289. try {
  1290. ProbeForWrite( pIcaEndpoint, sizeof(PVOID), 1 );
  1291. *((PVOID *)pIcaEndpoint) = Handle;
  1292. *BytesReturned = sizeof(PVOID);
  1293. } except(EXCEPTION_EXECUTE_HANDLER) {
  1294. Status = GetExceptionCode();
  1295. DBGPRINT(("DeviceConnectionRequest: Exception returning result 0x%x\n",Status));
  1296. }
  1297. // Exception
  1298. if( !NT_SUCCESS(Status) ) {
  1299. goto badsetup;
  1300. }
  1301. pConnectionEndpoint->hIcaHandle = Handle;
  1302. /*
  1303. * Save the file/device objects used for I/O in the TD structure
  1304. */
  1305. pTd->pFileObject = pTdTdi->pConnectionEndpoint->pFileObject;
  1306. pTd->pDeviceObject = pTdTdi->pConnectionEndpoint->pDeviceObject;
  1307. TRACE0(("DeviceConnectionRequest: New Connection Endpoint 0x%x Returned on Context 0x%x, AddressEndpoint 0x%x\n",pConnectionEndpoint,pTd->pAfd,pAddressEndpoint));
  1308. TRACE0(("FO 0x%x, DO 0x%x, Handle 0x%x\n",pConnectionEndpoint->pFileObject,pConnectionEndpoint->pDeviceObject,pConnectionEndpoint->TransportHandle));
  1309. //**********************************************************************************
  1310. // should be a success
  1311. return Status;
  1312. /*=============================================================================
  1313. == Error returns
  1314. =============================================================================*/
  1315. badsetup:
  1316. {
  1317. ULONG Length;
  1318. NTSTATUS Status2;
  1319. DBGPRINT(("DeviceConnectionRequest: Exception returning result 0x%x\n",Status));
  1320. Status2 = IcaCloseHandle( Handle, &pStackEndpoint, &Length );
  1321. if( NT_SUCCESS(Status2) ) {
  1322. MemoryFree( pStackEndpoint );
  1323. }
  1324. }
  1325. badconnect:
  1326. _TdCloseEndpoint(pTd, pConnectionEndpoint);
  1327. pTdTdi->pConnectionEndpoint = NULL;
  1328. badconnect1:
  1329. //
  1330. // It is imperative that we do not close address end point,
  1331. // We will close address end point on next IOCTL call which triggle
  1332. // Closing of address end point, if we do it here, we will end up
  1333. // double free and bug check.
  1334. // _TdCloseEndpoint(pTd, pAddressEndpoint);
  1335. badcreate:
  1336. if ( TransportName.Buffer )
  1337. MemoryFree( TransportName.Buffer );
  1338. if ( pTransportAddress )
  1339. MemoryFree( pTransportAddress );
  1340. if ( RemoteTransportName.Buffer )
  1341. MemoryFree( RemoteTransportName.Buffer );
  1342. if ( pRemoteTransportAddress )
  1343. MemoryFree( pRemoteTransportAddress );
  1344. badaddress:
  1345. done:
  1346. return Status;
  1347. }
  1348. /*******************************************************************************
  1349. * DeviceIoctl
  1350. *
  1351. * Query/Set configuration information for the td.
  1352. *
  1353. * pTd (input)
  1354. * Pointer to TD data structure
  1355. * pSdIoctl (input/output)
  1356. * Points to the parameter structure SD_IOCTL
  1357. ******************************************************************************/
  1358. NTSTATUS DeviceIoctl(PTD pTd, PSD_IOCTL pSdIoctl)
  1359. {
  1360. DBGENTER(("DeviceIoctl: PTD 0x%x\n",pTd));
  1361. return STATUS_NOT_SUPPORTED;
  1362. }
  1363. /*******************************************************************************
  1364. * DeviceInitializeRead
  1365. *
  1366. * Setup the IRP for a TDI read.
  1367. *
  1368. * pTd (input)
  1369. * Pointer to TD data structure
  1370. ******************************************************************************/
  1371. NTSTATUS DeviceInitializeRead(PTD pTd, PINBUF pInBuf)
  1372. {
  1373. PIRP Irp;
  1374. PTDTDI pTdTdi;
  1375. PIO_STACK_LOCATION _IRPSP;
  1376. pTdTdi = (PTDTDI) pTd->pAfd;
  1377. ASSERT( pTdTdi != NULL );
  1378. ASSERT( pTdTdi->pConnectionEndpoint != NULL );
  1379. ASSERT( pTd );
  1380. ASSERT( pTd->pDeviceObject );
  1381. ASSERT( !(pTd->pDeviceObject->Flags & DO_BUFFERED_IO) );
  1382. Irp = pInBuf->pIrp;
  1383. _IRPSP = IoGetNextIrpStackLocation( Irp );
  1384. ASSERT( Irp->MdlAddress == NULL );
  1385. /*
  1386. * TDI interfaces always use an MDL regardless of the driver I/O type.
  1387. */
  1388. MmInitializeMdl( pInBuf->pMdl, pInBuf->pBuffer, pTd->InBufHeader + pTd->OutBufLength );
  1389. MmBuildMdlForNonPagedPool( pInBuf->pMdl );
  1390. Irp->MdlAddress = pInBuf->pMdl;
  1391. if( pTdTdi->pConnectionEndpoint->EndpointType == TdiConnectionStream ) {
  1392. PTDI_REQUEST_KERNEL_RECEIVE p;
  1393. KIRQL OldIrql;
  1394. NTSTATUS Status;
  1395. PTD_ENDPOINT pEndpoint = pTdTdi->pConnectionEndpoint;
  1396. ASSERT( TdiDeviceEndpointType == TdiConnectionStream );
  1397. /*
  1398. * Most TDI users use the macro TdiBuildReceive(), but since
  1399. * our caller has already fiddled with the IrpStackLocation,
  1400. * we must do it inline.
  1401. */
  1402. _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1403. _IRPSP->MinorFunction = TDI_RECEIVE;
  1404. ASSERT( _IRPSP->DeviceObject == pTd->pDeviceObject );
  1405. ASSERT( _IRPSP->FileObject == pTd->pFileObject );
  1406. ASSERT( Irp->MdlAddress );
  1407. // Cast the generic parameters field to the TDI structure needed
  1408. p = (PTDI_REQUEST_KERNEL_RECEIVE)&_IRPSP->Parameters;
  1409. p->ReceiveFlags = 0;
  1410. p->ReceiveLength = pTd->InBufHeader + pTd->OutBufLength;
  1411. return( STATUS_SUCCESS );
  1412. }
  1413. else if( pTdTdi->pConnectionEndpoint->EndpointType == TdiConnectionDatagram ) {
  1414. PTDI_REQUEST_KERNEL_RECEIVEDG p;
  1415. ASSERT( TdiDeviceEndpointType == TdiConnectionDatagram );
  1416. /*
  1417. * Most TDI users use the macro TdiBuildReceiveDatagram(), but since
  1418. * our caller has already fiddled with the IrpStackLocation,
  1419. * we must do it inline.
  1420. */
  1421. _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1422. _IRPSP->MinorFunction = TDI_RECEIVE_DATAGRAM;
  1423. ASSERT( _IRPSP->DeviceObject );
  1424. ASSERT( _IRPSP->FileObject );
  1425. ASSERT( Irp->MdlAddress );
  1426. // Cast the generic parameters field to the TDI structure needed
  1427. p = (PTDI_REQUEST_KERNEL_RECEIVEDG)&_IRPSP->Parameters;
  1428. p->ReceiveFlags = 0;
  1429. p->ReceiveLength = pTd->InBufHeader + pTd->OutBufLength;
  1430. p->ReceiveDatagramInformation = NULL;
  1431. p->ReturnDatagramInformation = NULL;
  1432. return( STATUS_SUCCESS );
  1433. }
  1434. else {
  1435. DBGPRINT(("DeviceInitializeRead: Bad EndpointType 0x%x\n",pTdTdi->pConnectionEndpoint->EndpointType));
  1436. return( STATUS_INVALID_HANDLE );
  1437. }
  1438. // NOTREACHED
  1439. }
  1440. /*******************************************************************************
  1441. * DeviceSubmitRead
  1442. *
  1443. * Submit the read IRP to the driver.
  1444. ******************************************************************************/
  1445. NTSTATUS DeviceSubmitRead(PTD pTd, PINBUF pInBuf)
  1446. {
  1447. NTSTATUS Status;
  1448. PIRP Irp;
  1449. PTDTDI pTdTdi;
  1450. KIRQL OldIrql;
  1451. PLIST_ENTRY pEntry;
  1452. PTD_ENDPOINT pEndpoint;
  1453. PIO_STACK_LOCATION _IRPSP;
  1454. PTDI_REQUEST_KERNEL_RECEIVE p;
  1455. Irp = pInBuf->pIrp;
  1456. /*
  1457. * Datagram endpoints do not use a receive indication handler.
  1458. */
  1459. if( TdiDeviceEndpointType == TdiConnectionDatagram ) {
  1460. Status = IoCallDriver( pTd->pDeviceObject, Irp );
  1461. return( Status );
  1462. }
  1463. pTdTdi = (PTDTDI) pTd->pAfd;
  1464. ASSERT( pTdTdi != NULL );
  1465. ASSERT( pTdTdi->pConnectionEndpoint != NULL );
  1466. pEndpoint = pTdTdi->pConnectionEndpoint;
  1467. ExAcquireSpinLock( &pEndpoint->Spinlock, &OldIrql );
  1468. // The other end may have disconnected
  1469. if( pEndpoint->Disconnected ) {
  1470. TRACE0(("DeviceSubmitRead: Connection disconnecting! pEndpoint 0x%x\n",pEndpoint));
  1471. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  1472. Irp->IoStatus.Status = STATUS_REMOTE_DISCONNECT;
  1473. Irp->IoStatus.Information = 0;
  1474. // Since the IRP has not been submitted with IoCallDriver() yet,
  1475. // we must simulate.
  1476. IoSetNextIrpStackLocation( Irp );
  1477. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1478. return STATUS_REMOTE_DISCONNECT;
  1479. }
  1480. /*
  1481. * We queue the receive IRP onto the connection
  1482. * endpoint so that the indication handler can
  1483. * submit it. Because we could have received an
  1484. * indication while processing the previous receive,
  1485. * the indication will set the indicated byte count
  1486. * in RecvBytesReady that the call side can submit the IRP.
  1487. *
  1488. * The ReceiveQueue is designed to allow our caller to submit
  1489. * multiple read IRP's in case we need to handle a TDI
  1490. * provider that drops data when no receives are ready.
  1491. */
  1492. InsertTailList( &pEndpoint->ReceiveQueue, &Irp->Tail.Overlay.ListEntry );
  1493. /*
  1494. * Connection oriented endpoints disconnect the connection when
  1495. * a submitted I/O is canceled. This breaks the Citrix disconnect
  1496. * reconnect sequence that occurs on a new connection since the
  1497. * reader thread must be killed on one winstation, and the
  1498. * connection passed to another reader thread for a different
  1499. * winstation.
  1500. *
  1501. * This problem is solved by using a receive indication handler
  1502. * and only submitting IRP's when we know we will not block.
  1503. * This allows us to "cancel" I/O within our driver, and not
  1504. * have to do a IoCancelIrp() onto the TDI provider.
  1505. */
  1506. if( pEndpoint->RecvBytesReady ) {
  1507. //
  1508. // Indication came in without IRP ready, or more bytes indicated than
  1509. // ICA outbuf IRP can handle.
  1510. //
  1511. // We subtract the number of bytes we can receive from the indication
  1512. // bytes. We do not need to handle the IRP cancel case, since the TDI
  1513. // will nuke the connection anyway.
  1514. //
  1515. ASSERT( !IsListEmpty( &pEndpoint->ReceiveQueue ) );
  1516. pEntry = RemoveHeadList( &pEndpoint->ReceiveQueue );
  1517. Irp = CONTAINING_RECORD( pEntry, IRP, Tail.Overlay.ListEntry );
  1518. _IRPSP = IoGetNextIrpStackLocation( Irp );
  1519. p = (PTDI_REQUEST_KERNEL_RECEIVE)&_IRPSP->Parameters;
  1520. if( p->ReceiveLength > pEndpoint->RecvBytesReady ) {
  1521. pEndpoint->RecvBytesReady = 0;
  1522. }
  1523. else {
  1524. pEndpoint->RecvBytesReady -= p->ReceiveLength;
  1525. }
  1526. TRACE1(("DeviceSubmitRead: RecvBytesReady, Calling Driver with IRP 0x%x\n",Irp));
  1527. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  1528. Status = IoCallDriver( pTd->pDeviceObject, Irp );
  1529. return( Status );
  1530. }
  1531. else {
  1532. // In this case we let the indication handler submit it.
  1533. TRACE1(("DeviceSubmitRead: Letting indication handler submit. Irp 0x%x\n",Irp));
  1534. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  1535. return( STATUS_SUCCESS );
  1536. }
  1537. }
  1538. /*******************************************************************************
  1539. * DeviceWaitForRead
  1540. ******************************************************************************/
  1541. NTSTATUS DeviceWaitForRead(PTD pTd)
  1542. {
  1543. /*
  1544. * Just wait on the input event and return the wait status
  1545. */
  1546. return IcaWaitForSingleObject(pTd->pContext, &pTd->InputEvent, -1);
  1547. }
  1548. /*******************************************************************************
  1549. * DeviceReadComplete
  1550. *
  1551. * pTd (input)
  1552. * Pointer to TD data structure
  1553. * pBuffer (input)
  1554. * Pointer to input buffer
  1555. * pByteCount (input/output)
  1556. * Pointer to location to return byte count read
  1557. ******************************************************************************/
  1558. NTSTATUS DeviceReadComplete(PTD pTd, PUCHAR pBuffer, PULONG pByteCount)
  1559. {
  1560. /*
  1561. * Do any protocol specific read complete processing
  1562. */
  1563. return TdiDeviceReadComplete(pTd, pBuffer, pByteCount);
  1564. }
  1565. /*******************************************************************************
  1566. * DeviceInitializeWrite
  1567. ******************************************************************************/
  1568. NTSTATUS DeviceInitializeWrite(PTD pTd, POUTBUF pOutBuf)
  1569. {
  1570. PIRP Irp;
  1571. PTDTDI pTdTdi;
  1572. ULONG WriteLength;
  1573. PIO_STACK_LOCATION _IRPSP;
  1574. pTdTdi = (PTDTDI) pTd->pAfd;
  1575. ASSERT( pTdTdi != NULL );
  1576. ASSERT( pTdTdi->pConnectionEndpoint != NULL );
  1577. ASSERT( pTd );
  1578. ASSERT( pTd->pDeviceObject );
  1579. Irp = pOutBuf->pIrp;
  1580. _IRPSP = IoGetNextIrpStackLocation(Irp);
  1581. ASSERT(Irp->MdlAddress == NULL);
  1582. /*
  1583. * TDI interfaces always use an MDL regardless of the driver I/O type.
  1584. */
  1585. MmInitializeMdl(pOutBuf->pMdl, pOutBuf->pBuffer, pOutBuf->ByteCount);
  1586. MmBuildMdlForNonPagedPool(pOutBuf->pMdl);
  1587. Irp->MdlAddress = pOutBuf->pMdl;
  1588. if (pTdTdi->pConnectionEndpoint->EndpointType == TdiConnectionStream) {
  1589. PTDI_REQUEST_KERNEL_SEND p;
  1590. /*
  1591. * Most TDI users use the macro TdiBuildSend(), but since
  1592. * our caller has already fiddled with the IrpStackLocation,
  1593. * we must do it inline.
  1594. */
  1595. ASSERT( TdiDeviceEndpointType == TdiConnectionStream );
  1596. /*
  1597. * Now write in the reformatted parameters for a TDI SEND
  1598. */
  1599. _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1600. _IRPSP->MinorFunction = TDI_SEND;
  1601. ASSERT( _IRPSP->DeviceObject == pTd->pDeviceObject );
  1602. ASSERT( _IRPSP->FileObject == pTd->pFileObject );
  1603. ASSERT( Irp->MdlAddress );
  1604. p = (PTDI_REQUEST_KERNEL_SEND)&_IRPSP->Parameters;
  1605. p->SendFlags = 0;
  1606. p->SendLength = pOutBuf->ByteCount;
  1607. return STATUS_SUCCESS;
  1608. }
  1609. else if (pTdTdi->pConnectionEndpoint->EndpointType ==
  1610. TdiConnectionDatagram) {
  1611. PTDI_REQUEST_KERNEL_SENDDG p;
  1612. /*
  1613. * Most TDI users use the macro TdiBuildSendDatagram(), but since
  1614. * our caller has already fiddled with the IrpStackLocation,
  1615. * we must do it inline.
  1616. */
  1617. ASSERT( TdiDeviceEndpointType == TdiConnectionDatagram );
  1618. /*
  1619. * Now write in the reformatted parameters for a TDI SEND
  1620. */
  1621. _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1622. _IRPSP->MinorFunction = TDI_SEND_DATAGRAM;
  1623. ASSERT( _IRPSP->DeviceObject );
  1624. ASSERT( _IRPSP->FileObject );
  1625. ASSERT( Irp->MdlAddress );
  1626. p = (PTDI_REQUEST_KERNEL_SENDDG)&_IRPSP->Parameters;
  1627. p->SendLength = pOutBuf->ByteCount;
  1628. // Include the remote address with every datagram send
  1629. p->SendDatagramInformation = &pTdTdi->pConnectionEndpoint->SendInfo;
  1630. return STATUS_SUCCESS;
  1631. }
  1632. else {
  1633. DBGPRINT(("DeviceInitializeWrite: Bad EndpointType 0x%x\n",
  1634. pTdTdi->pConnectionEndpoint->EndpointType));
  1635. ASSERT(FALSE); // Catch this
  1636. return STATUS_INVALID_HANDLE;
  1637. }
  1638. }
  1639. /*******************************************************************************
  1640. * DeviceWaitForStatus
  1641. *
  1642. * Wait for device status to change (unused for network TDs)
  1643. ******************************************************************************/
  1644. NTSTATUS DeviceWaitForStatus(PTD pTd)
  1645. {
  1646. DBGENTER(("DeviceWaitForStatus: PTD 0x%x\n",pTd));
  1647. return STATUS_INVALID_DEVICE_REQUEST;
  1648. }
  1649. /*******************************************************************************
  1650. * DeviceCancelIo
  1651. *
  1652. * cancel all current and future i/o
  1653. ******************************************************************************/
  1654. NTSTATUS DeviceCancelIo(PTD pTd)
  1655. {
  1656. KIRQL OldIrql;
  1657. PTDTDI pTdTdi;
  1658. PIRP Irp;
  1659. PLIST_ENTRY pEntry;
  1660. PTD_ENDPOINT pEndpoint;
  1661. POUTBUF pOutBuf;
  1662. DBGENTER(("DeviceCancelIo: PTD 0x%x\n", pTd));
  1663. pTdTdi = (PTDTDI)pTd->pAfd;
  1664. ASSERT(pTdTdi != NULL);
  1665. if ((pEndpoint = pTdTdi->pConnectionEndpoint) != NULL ) {
  1666. DBGPRINT(("DeviceCancelIo [%p]: Endpoint 0x%p\n", pTd, pEndpoint));
  1667. // DbgPrint("DeviceCancelIo [0x%p]: Endpoint 0x%p, connected = %ld, disconnected = %ld\n",
  1668. // pTd, pEndpoint, pEndpoint->Connected, pEndpoint->Disconnected);
  1669. /*
  1670. * Disconnect the endpoint first to make all the I/O activity stop!
  1671. */
  1672. if (pEndpoint->Connected) {
  1673. NTSTATUS Status;
  1674. Status = _TdiDisconnect(pTd,
  1675. pEndpoint->pFileObject,
  1676. pEndpoint->pDeviceObject);
  1677. pEndpoint->Connected = FALSE;
  1678. }
  1679. /*
  1680. * Cancel any pended receives
  1681. */
  1682. _TdCancelReceiveQueue(pTd, pEndpoint, STATUS_LOCAL_DISCONNECT);
  1683. /*
  1684. * We now check to see if we have send IRP's on the
  1685. * outgoing queue that have been submitted to the TDI.
  1686. * When we register a disconnect indication handler, the TDI
  1687. * provider will not cancel IRP's when the connection drops.
  1688. * They will hang waiting to send on a connection that no longer
  1689. * is taking data.
  1690. *
  1691. * NOTE: We should be protected by the stack driver lock
  1692. * while we walk this chain.
  1693. */
  1694. pEntry = pTd->IoBusyOutBuf.Flink;
  1695. while (pEntry != &pTd->IoBusyOutBuf) {
  1696. pOutBuf = CONTAINING_RECORD(pEntry, OUTBUF, Links);
  1697. ASSERT(pOutBuf->pIrp != NULL);
  1698. // We must not cancel IRPs that have already completed.
  1699. if (!pOutBuf->fIrpCompleted) {
  1700. TRACE0(("DeviceCancelIo: Canceling Write IRP 0x%p Endpoint 0x%p\n",
  1701. pOutBuf->pIrp, pEndpoint));
  1702. IoCancelIrp(pOutBuf->pIrp);
  1703. }
  1704. pEntry = pEntry->Flink;
  1705. }
  1706. }
  1707. else
  1708. DBGPRINT(("DeviceCancelIo [0x%p]: Endpoint is NULL\n", pTd));
  1709. return STATUS_SUCCESS;
  1710. }
  1711. /*******************************************************************************
  1712. * DeviceSetParams
  1713. *
  1714. * Set device pararameters (unused for network TDs)
  1715. ******************************************************************************/
  1716. NTSTATUS DeviceSetParams(PTD pTd)
  1717. {
  1718. DBGENTER(("DeviceSetParams: PTD 0x%x\n", pTd));
  1719. return STATUS_SUCCESS;
  1720. }
  1721. /*******************************************************************************
  1722. * DeviceGetLastError
  1723. *
  1724. * This routine returns the last transport error code and message
  1725. *
  1726. * pTd (input)
  1727. * Pointer to TD data structure
  1728. * pLastError (output)
  1729. * address to return information on last transport error
  1730. ******************************************************************************/
  1731. NTSTATUS DeviceGetLastError(PTD pTd, PICA_STACK_LAST_ERROR pLastError)
  1732. {
  1733. DBGENTER(("DeviceGetLastError: PTD 0x%x\n",pTd));
  1734. return STATUS_SUCCESS;
  1735. }
  1736. /*******************************************************************************
  1737. * _TdCreateEndpointStruct
  1738. *
  1739. * Create and initialize a new Endpoint structure. Does not create any
  1740. * TDI objects.
  1741. *
  1742. * pTd (input)
  1743. * Pointer to TD data structure
  1744. * pTransportName (input)
  1745. * Pointer to UNICODE_STRING containing transport device name
  1746. * ppEndpoint (output)
  1747. * Pointer to location to return TD_ENDPOINT pointer
  1748. ******************************************************************************/
  1749. NTSTATUS _TdCreateEndpointStruct(
  1750. IN PTD pTd,
  1751. IN PUNICODE_STRING pTransportName,
  1752. OUT PTD_ENDPOINT *ppEndpoint,
  1753. IN PTRANSPORT_ADDRESS pTransportAddress,
  1754. IN ULONG TransportAddressLength)
  1755. {
  1756. NTSTATUS Status;
  1757. ULONG Length;
  1758. PTD_ENDPOINT pEndpoint;
  1759. NTSTATUS Status2;
  1760. PVOID pContext;
  1761. ULONG ContextLength;
  1762. /*
  1763. * Allocate an endpoint object and room for the transport name
  1764. */
  1765. Length = sizeof(*pEndpoint) + pTransportName->MaximumLength;
  1766. Status = MemoryAllocate(Length, &pEndpoint);
  1767. if (NT_SUCCESS(Status)) {
  1768. RtlZeroMemory(pEndpoint, Length);
  1769. Status = IcaCreateHandle( (PVOID)pEndpoint, sizeof(TD_ENDPOINT), &pEndpoint->hConnectionEndPointIcaHandle );
  1770. if (!NT_SUCCESS(Status)) {
  1771. MemoryFree(pEndpoint);
  1772. return Status;
  1773. }
  1774. } else {
  1775. return Status;
  1776. }
  1777. KeInitializeSpinLock( &pEndpoint->Spinlock );
  1778. KeInitializeEvent( &pEndpoint->AcceptEvent, NotificationEvent, FALSE );
  1779. InitializeListHead( &pEndpoint->ConnectionQueue );
  1780. InitializeListHead( &pEndpoint->ConnectedQueue );
  1781. InitializeListHead( &pEndpoint->AcceptQueue );
  1782. InitializeListHead( &pEndpoint->ReceiveQueue );
  1783. /*
  1784. * Build the transport name UNICODE_STRING and copy it
  1785. */
  1786. pEndpoint->TransportName.Length = pTransportName->Length;
  1787. pEndpoint->TransportName.MaximumLength = pTransportName->MaximumLength;
  1788. pEndpoint->TransportName.Buffer = (PWCHAR)(pEndpoint + 1);
  1789. RtlCopyMemory( pEndpoint->TransportName.Buffer, pTransportName->Buffer,
  1790. pTransportName->MaximumLength );
  1791. /*
  1792. * If a transport address is supplied, copy it in.
  1793. */
  1794. if (pTransportAddress && TransportAddressLength) {
  1795. /*
  1796. * Allocate and copy the transport address
  1797. */
  1798. Status = MemoryAllocate(TransportAddressLength,
  1799. &pEndpoint->pTransportAddress);
  1800. if (NT_SUCCESS(Status)) {
  1801. Status = IcaCreateHandle( (PVOID)pEndpoint->pTransportAddress, sizeof(TRANSPORT_ADDRESS), &pEndpoint->hTransportAddressIcaHandle );
  1802. if (!NT_SUCCESS(Status)) {
  1803. Status2 = IcaCloseHandle( pEndpoint->hConnectionEndPointIcaHandle , &pContext, &ContextLength );
  1804. MemoryFree(pEndpoint->pTransportAddress);
  1805. MemoryFree(pEndpoint);
  1806. return Status;
  1807. }
  1808. RtlCopyMemory(pEndpoint->pTransportAddress, pTransportAddress,
  1809. TransportAddressLength);
  1810. pEndpoint->TransportAddressLength = TransportAddressLength;
  1811. }
  1812. else {
  1813. Status2 = IcaCloseHandle( pEndpoint->hConnectionEndPointIcaHandle , &pContext, &ContextLength );
  1814. MemoryFree(pEndpoint);
  1815. return Status;
  1816. }
  1817. }
  1818. *ppEndpoint = pEndpoint;
  1819. return STATUS_SUCCESS;
  1820. }
  1821. /*******************************************************************************
  1822. * _TdCloseEndpoint
  1823. *
  1824. * Close a TDI endpoint object
  1825. *
  1826. * pTd (input)
  1827. * Pointer to TD data structure
  1828. * pEndpoint (input)
  1829. * Pointer TD_ENDPOINT object
  1830. ******************************************************************************/
  1831. NTSTATUS _TdCloseEndpoint(IN PTD pTd, IN PTD_ENDPOINT pEndpoint)
  1832. {
  1833. KIRQL OldIrql;
  1834. NTSTATUS Status;
  1835. PTDTDI pAfd;
  1836. PVOID pContext;
  1837. ULONG ContextLength ;
  1838. NTSTATUS Status2;
  1839. TRACE0(("_TdCloseEndpoint: pEndpoint 0x%x Context 0x%x Type 0x%x FO 0x%x, "
  1840. "DO 0x%x, Handle 0x%x\n", pEndpoint,pTd->pAfd,
  1841. pEndpoint->EndpointType, pEndpoint->pFileObject,
  1842. pEndpoint->pDeviceObject, pEndpoint->TransportHandle));
  1843. /*
  1844. * If this is an address endpoint, we could have
  1845. * a thread waiting for a connection.
  1846. *
  1847. * NOTE: Closing an address endpoint causes TDI to nuke all of the
  1848. * open connections that were created from it. Our upper
  1849. * level caller code understands this.
  1850. */
  1851. if (pEndpoint->EndpointType == TdiAddressObject) {
  1852. PTD_ENDPOINT p;
  1853. PLIST_ENTRY pEntry;
  1854. ExAcquireSpinLock(&pEndpoint->Spinlock, &OldIrql);
  1855. while (pEndpoint->Waiter) {
  1856. TRACE0(("_TdCloseEndpoint: Closing AddressEndpoint, Cleaning up listen thread...\n"));
  1857. KeSetEvent( &pEndpoint->AcceptEvent, IO_NETWORK_INCREMENT, FALSE );
  1858. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  1859. IcaSleep( pTd->pContext, 100 );
  1860. ExAcquireSpinLock( &pEndpoint->Spinlock, &OldIrql );
  1861. }
  1862. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  1863. /*
  1864. * Cancel the accept indication handler if necessary
  1865. * (FileObject may not be present if DeviceCreateEndpoint fails).
  1866. */
  1867. if (( TdiDeviceEndpointType != TdiConnectionDatagram ) &&
  1868. (pEndpoint->pFileObject)) {
  1869. Status = _TdiSetEventHandler(
  1870. pTd,
  1871. pEndpoint->pDeviceObject,
  1872. pEndpoint->pFileObject,
  1873. TDI_EVENT_CONNECT,
  1874. (PVOID)NULL, // Handler
  1875. (PVOID)NULL // Context
  1876. );
  1877. ASSERT( NT_SUCCESS(Status) );
  1878. }
  1879. /*
  1880. * Free the connection object queues.
  1881. *
  1882. * NOTE: We no longer need the spinlock since we have
  1883. * cancelled the connect indication handler from TDI,
  1884. * and the upper level protects calls to teardown an
  1885. * address endpoint.
  1886. */
  1887. /*
  1888. * Cleanup connected, but not returned objects
  1889. */
  1890. while( !IsListEmpty( &pEndpoint->ConnectedQueue ) ) {
  1891. pEntry = pEndpoint->ConnectedQueue.Flink;
  1892. RemoveEntryList( pEntry );
  1893. p = CONTAINING_RECORD( pEntry, TD_ENDPOINT, ConnectionLink );
  1894. ASSERT( p->EndpointType != TdiAddressObject );
  1895. _TdCloseEndpoint( pTd, p );
  1896. }
  1897. /*
  1898. * Cleanup queue of wait for Accept complete connections
  1899. */
  1900. while( !IsListEmpty( &pEndpoint->AcceptQueue ) ) {
  1901. pEntry = pEndpoint->AcceptQueue.Flink;
  1902. RemoveEntryList( pEntry );
  1903. p = CONTAINING_RECORD( pEntry, TD_ENDPOINT, ConnectionLink );
  1904. ASSERT( p->EndpointType != TdiAddressObject );
  1905. _TdCloseEndpoint( pTd, p );
  1906. }
  1907. /*
  1908. * Cleanup queue of empty connections
  1909. */
  1910. while( !IsListEmpty( &pEndpoint->ConnectionQueue ) ) {
  1911. pEntry = pEndpoint->ConnectionQueue.Flink;
  1912. RemoveEntryList( pEntry );
  1913. p = CONTAINING_RECORD( pEntry, TD_ENDPOINT, ConnectionLink );
  1914. ASSERT( p->EndpointType != TdiAddressObject );
  1915. _TdCloseEndpoint( pTd, p );
  1916. }
  1917. }
  1918. /*
  1919. * If this endpoint has ever been connected,
  1920. * then tell the transport driver we are closing down.
  1921. */
  1922. if (pEndpoint->Connected) {
  1923. (VOID) _TdiDisconnect(pTd,
  1924. pEndpoint->pFileObject,
  1925. pEndpoint->pDeviceObject);
  1926. }
  1927. pEndpoint->pDeviceObject = NULL;
  1928. /*
  1929. * If a file object, dereference it
  1930. */
  1931. if (pEndpoint->pFileObject) {
  1932. ObDereferenceObject( pEndpoint->pFileObject );
  1933. pEndpoint->pFileObject = NULL;
  1934. }
  1935. /*
  1936. * If a file handle, close it
  1937. */
  1938. if (pEndpoint->TransportHandle) {
  1939. ASSERT( pEndpoint->TransportHandleProcess == IoGetCurrentProcess() );
  1940. ZwClose( pEndpoint->TransportHandle );
  1941. pEndpoint->TransportHandleProcess = NULL;
  1942. pEndpoint->TransportHandle = NULL;
  1943. }
  1944. /*
  1945. * If an IRP, free it
  1946. *
  1947. * NOTE: This must be *AFTER* the close since the
  1948. * IRP is in the bowels of the TCP driver!
  1949. */
  1950. if( pEndpoint->AcceptIrp ) {
  1951. IoFreeIrp( pEndpoint->AcceptIrp );
  1952. pEndpoint->AcceptIrp = NULL;
  1953. }
  1954. /*
  1955. * If a transport address, free it, and Also close it handle if there is one.
  1956. */
  1957. if (pEndpoint->hTransportAddressIcaHandle != NULL) {
  1958. Status2 = IcaCloseHandle( pEndpoint->hTransportAddressIcaHandle , &pContext, &ContextLength );
  1959. }
  1960. if ( pEndpoint->pTransportAddress ) {
  1961. MemoryFree( pEndpoint->pTransportAddress );
  1962. pEndpoint->pTransportAddress = NULL;
  1963. }
  1964. /*
  1965. * If a remote address, free it
  1966. */
  1967. if ( pEndpoint->pRemoteAddress ) {
  1968. MemoryFree( pEndpoint->pRemoteAddress );
  1969. pEndpoint->pRemoteAddress = NULL;
  1970. }
  1971. if (pEndpoint->hConnectionEndPointIcaHandle != NULL) {
  1972. Status2 = IcaCloseHandle( pEndpoint->hConnectionEndPointIcaHandle , &pContext, &ContextLength );
  1973. }
  1974. DBGPRINT(("_TdCloseEndpoint [%p]: 0x%p\n", pTd, pEndpoint));
  1975. MemoryFree(pEndpoint);
  1976. return STATUS_SUCCESS;
  1977. }
  1978. /****************************************************************************/
  1979. // _TdConnectHandler
  1980. //
  1981. // This is the transport connect event handler for the server. It is
  1982. // specified as the connect handler for all endpoints opened by the
  1983. // server. It attempts to dequeue a free connection from a list
  1984. // anchored in the address endpoint. If successful, it returns the
  1985. // connection to the transport. Otherwise, the connection is rejected.
  1986. /****************************************************************************/
  1987. NTSTATUS _TdConnectHandler(
  1988. IN PVOID TdiEventContext,
  1989. IN int RemoteAddressLength,
  1990. IN PVOID RemoteAddress,
  1991. IN int UserDataLength,
  1992. IN PVOID UserData,
  1993. IN int OptionsLength,
  1994. IN PVOID Options,
  1995. OUT CONNECTION_CONTEXT *ConnectionContext,
  1996. OUT PIRP *AcceptIrp)
  1997. {
  1998. KIRQL OldIrql;
  1999. NTSTATUS Status;
  2000. PLIST_ENTRY pEntry;
  2001. PTD_ENDPOINT pConnection;
  2002. PTD_ENDPOINT pAddressEndpoint;
  2003. PACCEPT_CONTEXT Context;
  2004. UserDataLength, UserData; // avoid compiler warnings
  2005. OptionsLength, Options;
  2006. pAddressEndpoint = (PTD_ENDPOINT)TdiEventContext;
  2007. TRACE0(("_TdConnectHandler: Connect event! Context 0x%x\n",pAddressEndpoint));
  2008. /*
  2009. * First try and get memory. If error, the TDI transport provider
  2010. * will drop the connect request.
  2011. */
  2012. Status = MemoryAllocate(sizeof(ACCEPT_CONTEXT), &Context);
  2013. if (NT_SUCCESS(Status)) {
  2014. memset(Context, 0, sizeof(ACCEPT_CONTEXT));
  2015. }
  2016. else {
  2017. DBGPRINT(("_TdConnectHandler: No memory for context\n"));
  2018. return Status;
  2019. }
  2020. /*
  2021. * Get the spinlock to synchronize with the call side
  2022. */
  2023. ExAcquireSpinLock(&pAddressEndpoint->Spinlock, &OldIrql);
  2024. /*
  2025. * Get the connection object on the front of the list
  2026. */
  2027. if (!IsListEmpty(&pAddressEndpoint->ConnectionQueue)) {
  2028. pEntry = RemoveHeadList(&pAddressEndpoint->ConnectionQueue);
  2029. pConnection = CONTAINING_RECORD(pEntry, TD_ENDPOINT, ConnectionLink);
  2030. // Put it on the end of the accept list
  2031. InsertTailList(&pAddressEndpoint->AcceptQueue,
  2032. &pConnection->ConnectionLink);
  2033. }
  2034. else {
  2035. DBGPRINT(("_TdConnectHandler: Empty ConnectionQueue! 0x%x\n",
  2036. pAddressEndpoint));
  2037. ExReleaseSpinLock(&pAddressEndpoint->Spinlock, OldIrql);
  2038. MemoryFree(Context);
  2039. return STATUS_INSUFFICIENT_RESOURCES;
  2040. }
  2041. Context->pAddressEndpoint = pAddressEndpoint;
  2042. Context->pConnectionEndpoint = pConnection;
  2043. ASSERT(pConnection->AcceptIrp != NULL);
  2044. //
  2045. // remember the remote address in the connection endpoint
  2046. //
  2047. if ( NULL != RemoteAddress )
  2048. {
  2049. ASSERT( NULL == pConnection->pRemoteAddress );
  2050. ASSERT( 0 != RemoteAddressLength );
  2051. if ( NT_SUCCESS( MemoryAllocate( RemoteAddressLength, &pConnection->pRemoteAddress )))
  2052. {
  2053. RtlCopyMemory( pConnection->pRemoteAddress, RemoteAddress, RemoteAddressLength );
  2054. pConnection->RemoteAddressLength = RemoteAddressLength;
  2055. }
  2056. }
  2057. TdiBuildAccept(
  2058. pConnection->AcceptIrp,
  2059. pConnection->pDeviceObject,
  2060. pConnection->pFileObject,
  2061. _TdAcceptComplete, // Completion routine
  2062. Context, // Context
  2063. &Context->RequestInfo,
  2064. &Context->ReturnInfo);
  2065. /*
  2066. * Make the next stack location current. Normally IoCallDriver would
  2067. * do this, but since we're bypassing that, we do it directly.
  2068. */
  2069. IoSetNextIrpStackLocation(pConnection->AcceptIrp);
  2070. /*
  2071. * Return the connection context (the connection address) to the
  2072. * transport. Return a pointer to the Accept IRP. Indicate that
  2073. * the Connect event has been handled. This must be the same
  2074. * context specified when the connection object was created.
  2075. */
  2076. *ConnectionContext = pConnection;
  2077. *AcceptIrp = pConnection->AcceptIrp;
  2078. ExReleaseSpinLock(&pAddressEndpoint->Spinlock, OldIrql);
  2079. return STATUS_MORE_PROCESSING_REQUIRED;
  2080. }
  2081. NTSTATUS _TdAcceptComplete(
  2082. IN PDEVICE_OBJECT DeviceObject,
  2083. IN PIRP Irp,
  2084. IN PVOID Ctx)
  2085. {
  2086. KIRQL OldIrql;
  2087. PLIST_ENTRY pEntry;
  2088. PACCEPT_CONTEXT Context;
  2089. PTD_ENDPOINT pConnection;
  2090. PTD_ENDPOINT pAddressEndpoint;
  2091. Context = (PACCEPT_CONTEXT)Ctx;
  2092. pConnection = Context->pConnectionEndpoint;
  2093. pAddressEndpoint = Context->pAddressEndpoint;
  2094. ASSERT( pConnection != NULL );
  2095. ASSERT( pAddressEndpoint != NULL );
  2096. ASSERT( pConnection->EndpointType == TdiConnectionStream );
  2097. ASSERT( pAddressEndpoint->EndpointType == TdiAddressObject );
  2098. TRACE0(("_TdAcceptComplete: Status 0x%x, Endpoint 0x%x\n",Irp->IoStatus.Status,pConnection));
  2099. /*
  2100. * Get the spinlock to synchronize with the call side
  2101. */
  2102. ExAcquireSpinLock( &pAddressEndpoint->Spinlock, &OldIrql );
  2103. if (IsListEmpty( &pAddressEndpoint->AcceptQueue)) {
  2104. DBGPRINT(("_TdAcceptComplete: Empty Accept Queue! 0x%x\n",
  2105. pAddressEndpoint));
  2106. ExReleaseSpinLock(&pAddressEndpoint->Spinlock, OldIrql);
  2107. /*
  2108. * Release the context memory
  2109. */
  2110. MemoryFree(Context);
  2111. // Let it drop
  2112. return STATUS_MORE_PROCESSING_REQUIRED;
  2113. }
  2114. else {
  2115. pEntry = RemoveHeadList(&pAddressEndpoint->AcceptQueue);
  2116. pConnection = CONTAINING_RECORD(pEntry, TD_ENDPOINT, ConnectionLink);
  2117. /*
  2118. * Put it on the end of the connect list
  2119. */
  2120. InsertTailList(&pAddressEndpoint->ConnectedQueue,
  2121. &pConnection->ConnectionLink);
  2122. }
  2123. /*
  2124. * If the accept failed, the caller will check this status
  2125. * and tear down the connection, causing a RST to be sent
  2126. * to the other side.
  2127. */
  2128. pConnection->Status = Irp->IoStatus.Status;
  2129. /*
  2130. * Signal that it is connected (Could be in error)
  2131. */
  2132. pConnection->Connected = TRUE;
  2133. /*
  2134. * Set the event on the address object
  2135. */
  2136. KeSetEvent(&Context->pAddressEndpoint->AcceptEvent, IO_NETWORK_INCREMENT, FALSE);
  2137. ExReleaseSpinLock(&pAddressEndpoint->Spinlock, OldIrql);
  2138. /*
  2139. * Release the context memory
  2140. */
  2141. MemoryFree(Context);
  2142. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  2143. // will stop working on the IRP.
  2144. return STATUS_MORE_PROCESSING_REQUIRED;
  2145. }
  2146. /*****************************************************************************
  2147. * _TdReceiveHandler
  2148. *
  2149. * This function is called by the TDI when receive data is available
  2150. * on the connection. This is done so we do not submit the IRP until
  2151. * data is available. The disconnect-reconnect logic in ICA causes an
  2152. * IoCancelIrp() to be sent on the input thread, and TDI providers drop the
  2153. * connection on a read or write I/O cancel.
  2154. *
  2155. * WARNING: This critical behavior is only needed for a reconnect
  2156. * sequence. For normal ICA I/O, it is OK to block the reader
  2157. * thread in the TDI driver.
  2158. *
  2159. * TdiEventContext (input)
  2160. * Context registered with event handler on address object.
  2161. * (address endpoint)
  2162. *
  2163. * ConnectionContext (input)
  2164. * Connection context registered with the connection
  2165. * create.
  2166. ****************************************************************************/
  2167. NTSTATUS _TdReceiveHandler(
  2168. IN PVOID TdiEventContext,
  2169. IN CONNECTION_CONTEXT ConnectionContext,
  2170. IN ULONG ReceiveFlags,
  2171. IN ULONG BytesIndicated,
  2172. IN ULONG BytesAvailable,
  2173. OUT ULONG *BytesTaken,
  2174. IN PVOID Tsdu,
  2175. OUT PIRP *IoRequestPacket)
  2176. {
  2177. KIRQL OldIrql;
  2178. PIRP Irp;
  2179. PLIST_ENTRY pEntry;
  2180. PIO_STACK_LOCATION _IRPSP;
  2181. PTDI_REQUEST_KERNEL_RECEIVE p;
  2182. PTD_ENDPOINT pEndpoint = (PTD_ENDPOINT)ConnectionContext;
  2183. /*
  2184. * Only stream transports use a receive indication handler.
  2185. */
  2186. ASSERT( TdiDeviceEndpointType != TdiConnectionDatagram );
  2187. ASSERT( pEndpoint != NULL );
  2188. ASSERT( pEndpoint->EndpointType == TdiConnectionStream );
  2189. TRACE1(("_TdReceiveHandler: ReceiveDataIndication! pEndpoint 0x%x\n",pEndpoint));
  2190. ExAcquireSpinLock(&pEndpoint->Spinlock, &OldIrql);
  2191. *BytesTaken = 0;
  2192. /*
  2193. * Submit an IRP at indication time if we have one on
  2194. * the queue.
  2195. */
  2196. if (!IsListEmpty( &pEndpoint->ReceiveQueue)) {
  2197. pEntry = RemoveHeadList(&pEndpoint->ReceiveQueue);
  2198. Irp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  2199. TRACE1(("_TdReceiveHandler: Passing IRP for Receive Indication %d bytes\n",
  2200. BytesAvailable));
  2201. _IRPSP = IoGetNextIrpStackLocation(Irp);
  2202. p = (PTDI_REQUEST_KERNEL_RECEIVE)&_IRPSP->Parameters;
  2203. if (p->ReceiveLength < BytesAvailable) {
  2204. pEndpoint->RecvBytesReady += (BytesAvailable - p->ReceiveLength);
  2205. TRACE1(("_TdReceiveHandler: Excess Bytes %d Added to RecvBytesReady, now %d\n",
  2206. (BytesAvailable - p->ReceiveLength),
  2207. pEndpoint->RecvBytesReady));
  2208. }
  2209. ExReleaseSpinLock(&pEndpoint->Spinlock, OldIrql);
  2210. *IoRequestPacket = Irp;
  2211. IoSetNextIrpStackLocation(Irp);
  2212. return STATUS_MORE_PROCESSING_REQUIRED;
  2213. }
  2214. // No RecvIrp, So we can not take any data. Let the callside get it.
  2215. TRACE1(("_TdReceiveHandler: No RecvIrp, Adding To RecvBytesReady. %d Bytes\n",BytesAvailable));
  2216. pEndpoint->RecvBytesReady += BytesAvailable;
  2217. ExReleaseSpinLock(&pEndpoint->Spinlock, OldIrql);
  2218. return STATUS_DATA_NOT_ACCEPTED;
  2219. }
  2220. /*****************************************************************************
  2221. * _TdDisconnectHandler
  2222. *
  2223. * This function is called by the TDI when a disconnect occurs
  2224. * on the connection.
  2225. *
  2226. * TdiEventContext (input)
  2227. * Context registered with event handler on address object.
  2228. * (address endpoint)
  2229. *
  2230. * ConnectionContext (input)
  2231. * Connection context registered with the connection
  2232. * create.
  2233. ****************************************************************************/
  2234. NTSTATUS _TdDisconnectHandler(
  2235. IN PVOID TdiEventContext,
  2236. IN CONNECTION_CONTEXT ConnectionContext,
  2237. IN int DisconnectDataLength,
  2238. IN PVOID DisconnectData,
  2239. IN int DisconnectInformationLength,
  2240. IN PVOID DisconnectInformation,
  2241. IN ULONG DisconnectFlags)
  2242. {
  2243. KIRQL OldIrql;
  2244. PIRP Irp;
  2245. PIO_STACK_LOCATION irpSp;
  2246. PLIST_ENTRY pEntry;
  2247. PTD_ENDPOINT pEndpoint = (PTD_ENDPOINT)ConnectionContext;
  2248. /*
  2249. * Only stream transports use a disconnect indication handler.
  2250. */
  2251. ASSERT( TdiDeviceEndpointType != TdiConnectionDatagram );
  2252. ASSERT( pEndpoint != NULL );
  2253. ASSERT( pEndpoint->EndpointType == TdiConnectionStream );
  2254. // DbgPrint("\n");
  2255. // DbgPrint("_TdDisconnectHandler : pEndpoint = 0x%p\n", pEndpoint);
  2256. ExAcquireSpinLock( &pEndpoint->Spinlock, &OldIrql );
  2257. pEndpoint->Disconnected = TRUE;
  2258. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  2259. _TdCancelReceiveQueue(NULL, pEndpoint, STATUS_REMOTE_DISCONNECT );
  2260. return STATUS_SUCCESS;
  2261. }
  2262. /****************************************************************************/
  2263. // Create an idle connection object associated with an address object.
  2264. // This must be called from call (thread) level, and not from indication
  2265. // time (DPC level).
  2266. /****************************************************************************/
  2267. NTSTATUS _TdCreateConnectionObject(
  2268. IN PTD pTd,
  2269. IN PUNICODE_STRING pTransportName,
  2270. OUT PTD_ENDPOINT *ppEndpoint,
  2271. IN PTRANSPORT_ADDRESS pTransportAddress,
  2272. IN ULONG TransportAddressLength)
  2273. {
  2274. PTDTDI pTdTdi;
  2275. NTSTATUS Status;
  2276. PTD_ENDPOINT pEndpoint;
  2277. pTdTdi = (PTDTDI)pTd->pAfd;
  2278. // Create and init structure and spinlock
  2279. Status = _TdCreateEndpointStruct(
  2280. pTd,
  2281. pTransportName,
  2282. ppEndpoint,
  2283. pTransportAddress,
  2284. TransportAddressLength
  2285. );
  2286. if (NT_SUCCESS(Status)) {
  2287. pEndpoint = *ppEndpoint;
  2288. }
  2289. else {
  2290. return Status;
  2291. }
  2292. // The TD sets whether data gram, or stream
  2293. pEndpoint->EndpointType = TdiDeviceEndpointType;
  2294. pEndpoint->TransportHandleProcess = IoGetCurrentProcess();
  2295. /*
  2296. * Create a TDI connection object
  2297. */
  2298. Status = _TdiOpenConnection(
  2299. &pEndpoint->TransportName,
  2300. (PVOID)pEndpoint, // Context
  2301. &pEndpoint->TransportHandle,
  2302. &pEndpoint->pFileObject,
  2303. &pEndpoint->pDeviceObject
  2304. );
  2305. if (!NT_SUCCESS(Status)) {
  2306. DBGPRINT(("_TdCreateConnectionObject: _TdiOpenConnection failed, Status 0x%x\n",Status));
  2307. _TdCloseEndpoint( pTd, pEndpoint );
  2308. return Status;
  2309. }
  2310. // Allocate an IRP for connect/disconnect handling
  2311. // This is needed since we use the connect indication hander.
  2312. pEndpoint->AcceptIrp = _TdiAllocateIrp(pEndpoint->pFileObject,
  2313. pEndpoint->pDeviceObject);
  2314. if (pEndpoint->AcceptIrp == NULL) {
  2315. DBGPRINT(("_TdCreateConnectionObject: Could not allocate IRP\n"));
  2316. _TdCloseEndpoint(pTd, pEndpoint);
  2317. return STATUS_INSUFFICIENT_RESOURCES;
  2318. }
  2319. // Associate the connection object with its address object
  2320. Status = _TdiAssociateAddress(
  2321. pTd,
  2322. pEndpoint->AcceptIrp,
  2323. pEndpoint->pFileObject,
  2324. pTdTdi->pAddressEndpoint->TransportHandle,
  2325. pTdTdi->pAddressEndpoint->pDeviceObject
  2326. );
  2327. if (!NT_SUCCESS(Status)) {
  2328. DBGPRINT(("_TdCreateConnectionObject: _TdiAssociateAddress failed, Status 0x%x\n",Status));
  2329. _TdCloseEndpoint(pTd, pEndpoint);
  2330. return Status;
  2331. }
  2332. return Status;
  2333. }
  2334. /*******************************************************************************
  2335. * _TdWaitForDatagramConnection
  2336. *
  2337. * For for an incoming datagram connection request and accept it.
  2338. *
  2339. * Datagram endpoints listen on a TDI address object bound to the local
  2340. * (netcard) and well known ICA socket number. Packets then received on
  2341. * the ICA socket number are checked for ICA request connection, and then
  2342. * a new TDI address object is bound with the wild-card local address
  2343. * (0). This causes a new, unused socket number to be assigned to this
  2344. * address object. This new TDI address object is used for further
  2345. * communication to the now "connected" IPX ICA client.
  2346. *
  2347. * pTd (input)
  2348. * Pointer to TD data structure
  2349. * pAddressEndpoint (input)
  2350. * Pointer Address endpoint object
  2351. * ppConnectionEndpoint (output)
  2352. * Pointer to location to return Connection endpoint pointer
  2353. ******************************************************************************/
  2354. NTSTATUS _TdWaitForDatagramConnection(
  2355. IN PTD pTd,
  2356. IN PTD_ENDPOINT pAddressEndpoint,
  2357. OUT PTD_ENDPOINT *ppConnectionEndpoint)
  2358. {
  2359. NTSTATUS Status;
  2360. PTRANSPORT_ADDRESS pLocalAddress;
  2361. ULONG LocalAddressLength;
  2362. ULONG AddressInfoLength;
  2363. ULONG RemoteAddressLength = 0;
  2364. PTD_ENDPOINT pEndpoint = NULL;
  2365. PTRANSPORT_ADDRESS pRemoteAddress = NULL;
  2366. PTDI_ADDRESS_INFO pAddressInfo = NULL;
  2367. /*
  2368. * Get a copy of the local transport address.
  2369. *
  2370. * Clear the TDI address part of the structure so that we can
  2371. * use it to bind the connection endpoint to a wild-card address.
  2372. *
  2373. * This wildcard address (0), will cause the packet level TDI
  2374. * provider to assign us a unique socket when the TDI address
  2375. * object is created.
  2376. */
  2377. Status = MemoryAllocate(pAddressEndpoint->TransportAddressLength,
  2378. &pLocalAddress);
  2379. if (NT_SUCCESS(Status)) {
  2380. RtlCopyMemory(pLocalAddress, pAddressEndpoint->pTransportAddress,
  2381. pAddressEndpoint->TransportAddressLength);
  2382. RtlZeroMemory(pLocalAddress->Address[0].Address,
  2383. pLocalAddress->Address[0].AddressLength);
  2384. }
  2385. else {
  2386. goto badmalloc;
  2387. }
  2388. LocalAddressLength = pAddressEndpoint->TransportAddressLength;
  2389. /*
  2390. * Call protocol specific routine to wait for
  2391. * a datagram connection request to arrive.
  2392. *
  2393. * This returns when a valid ICA connect datagram comes in
  2394. * from a remote address. No reply has been sent.
  2395. */
  2396. Status = TdiDeviceWaitForDatagramConnection(pTd,
  2397. pAddressEndpoint->pFileObject,
  2398. pAddressEndpoint->pDeviceObject,
  2399. &pRemoteAddress,
  2400. &RemoteAddressLength);
  2401. if (!NT_SUCCESS(Status)) {
  2402. DBGPRINT(("_TdWaitForDatagramConnection: Error 0x%x in TdiDeviceWaitForDatagramConnction\n",Status));
  2403. goto badwait;
  2404. }
  2405. ASSERT( pRemoteAddress != NULL );
  2406. /*
  2407. * Create a new address endpoint bound to the wildcard local address.
  2408. * A unique "socket" will be created for us. This will become
  2409. * our datagram "connection".
  2410. */
  2411. Status = _TdCreateEndpointStruct(
  2412. pTd,
  2413. &pAddressEndpoint->TransportName,
  2414. &pEndpoint,
  2415. pLocalAddress,
  2416. LocalAddressLength
  2417. );
  2418. if ( !NT_SUCCESS( Status ) ) {
  2419. DBGPRINT(("_TdWaitForDatagramConnection: Error 0x%x in _TdCreateEndpointStruct\n",Status));
  2420. goto badopen;
  2421. }
  2422. pEndpoint->EndpointType = TdiConnectionDatagram;
  2423. pEndpoint->TransportHandleProcess = IoGetCurrentProcess();
  2424. /*
  2425. * Create the TDI address object.
  2426. */
  2427. Status = _TdiCreateAddress(
  2428. &pEndpoint->TransportName,
  2429. pEndpoint->pTransportAddress,
  2430. pEndpoint->TransportAddressLength,
  2431. &pEndpoint->TransportHandle,
  2432. &pEndpoint->pFileObject,
  2433. &pEndpoint->pDeviceObject
  2434. );
  2435. if ( !NT_SUCCESS( Status ) ) {
  2436. DBGPRINT(("_TdWaitForDatagramConnection: Error 0x%x in _TdiCreateAddress\n",Status));
  2437. goto badbind;
  2438. }
  2439. /*
  2440. * Allocate a work buffer for querying the transport address
  2441. */
  2442. AddressInfoLength = pEndpoint->TransportAddressLength+4;
  2443. Status = MemoryAllocate( AddressInfoLength, &pAddressInfo );
  2444. if ( !NT_SUCCESS( Status ) ) {
  2445. DBGPRINT(("_TdWaitForDatagramConnection: Error 0x%x Allocating Memory %d bytes\n",Status,AddressInfoLength));
  2446. goto badbind;
  2447. }
  2448. /*
  2449. * Now query the unique socket address that the TDI assigned for us.
  2450. */
  2451. Status = _TdiQueryAddressInfo(
  2452. pTd,
  2453. NULL, // Irp
  2454. pEndpoint->pFileObject,
  2455. pEndpoint->pDeviceObject,
  2456. pAddressInfo,
  2457. AddressInfoLength
  2458. );
  2459. if( !NT_SUCCESS(Status) ) {
  2460. DBGPRINT(("_TdWaitForDatagramConnection: Error 0x%x in _TdiQueryAddressInfo\n",Status));
  2461. goto badbind;
  2462. }
  2463. /*
  2464. * Update the callers transport address buffer
  2465. */
  2466. RtlCopyMemory( pEndpoint->pTransportAddress,
  2467. &pAddressInfo->Address,
  2468. pEndpoint->TransportAddressLength );
  2469. /*
  2470. * Save the remote address in the connection endpoint
  2471. * structure so that we can send to it with our datagram sends.
  2472. */
  2473. ASSERT( pEndpoint->pRemoteAddress == NULL );
  2474. pEndpoint->pRemoteAddress = pRemoteAddress;
  2475. pEndpoint->RemoteAddressLength = RemoteAddressLength;
  2476. pEndpoint->SendInfo.RemoteAddress = pRemoteAddress;
  2477. pEndpoint->SendInfo.RemoteAddressLength = RemoteAddressLength;
  2478. /*
  2479. * Call protocol specific routine to complete the datagram connection.
  2480. *
  2481. * This sends the ICA connect reply datagram.
  2482. */
  2483. Status = TdiDeviceCompleteDatagramConnection(
  2484. pTd,
  2485. pEndpoint->pFileObject,
  2486. pEndpoint->pDeviceObject,
  2487. pEndpoint->SendInfo.RemoteAddress,
  2488. pEndpoint->SendInfo.RemoteAddressLength
  2489. );
  2490. if (!NT_SUCCESS(Status)) {
  2491. DBGPRINT(("_TdWaitForDatagramConnection: Error 0x%x in TdiDeviceCompleteDatagramConnection\n",Status));
  2492. goto badcomplete;
  2493. }
  2494. *ppConnectionEndpoint = pEndpoint;
  2495. MemoryFree(pLocalAddress);
  2496. MemoryFree(pAddressInfo);
  2497. return STATUS_SUCCESS;
  2498. /*=============================================================================
  2499. == Error returns
  2500. =============================================================================*/
  2501. badcomplete:
  2502. badbind:
  2503. if (pEndpoint)
  2504. _TdCloseEndpoint(pTd, pEndpoint);
  2505. badopen:
  2506. if (pAddressInfo)
  2507. MemoryFree(pAddressInfo);
  2508. if (pRemoteAddress)
  2509. MemoryFree(pRemoteAddress);
  2510. badwait:
  2511. MemoryFree(pLocalAddress);
  2512. badmalloc:
  2513. return Status;
  2514. }
  2515. /*****************************************************************************
  2516. *
  2517. * returns the remote address
  2518. *
  2519. ****************************************************************************/
  2520. NTSTATUS DeviceQueryRemoteAddress(
  2521. PTD pTd,
  2522. PVOID pIcaEndpoint,
  2523. ULONG EndpointSize,
  2524. PVOID pOutputAddress,
  2525. ULONG OutputAddressSize,
  2526. PULONG BytesReturned)
  2527. {
  2528. NTSTATUS status = STATUS_NOT_SUPPORTED;
  2529. PTD_STACK_ENDPOINT pStackEndpoint;
  2530. PTRANSPORT_ADDRESS pRemoteAddress;
  2531. PTA_ADDRESS pRemoteIP;
  2532. PVOID Handle;
  2533. ULONG Length;
  2534. struct {
  2535. USHORT sa_family;
  2536. CHAR sa_data[1];
  2537. } *pOutput;
  2538. *BytesReturned = 0;
  2539. if ( sizeof(PVOID) != EndpointSize )
  2540. {
  2541. status = STATUS_INVALID_PARAMETER_4;
  2542. goto exitpt;
  2543. }
  2544. pOutput = pOutputAddress;
  2545. if ( NULL == pOutput )
  2546. {
  2547. status = STATUS_INVALID_PARAMETER_5;
  2548. goto exitpt;
  2549. }
  2550. try {
  2551. RtlZeroMemory( pOutput, OutputAddressSize );
  2552. } except ( EXCEPTION_EXECUTE_HANDLER )
  2553. {
  2554. status = GetExceptionCode();
  2555. DBGPRINT(("DeviceQueryRemoteAddress: Exception 0x%x\n", status));
  2556. goto exitpt;
  2557. }
  2558. /*
  2559. * Capture the parameter
  2560. */
  2561. try {
  2562. ProbeForRead( pIcaEndpoint, sizeof(PVOID), 1 );
  2563. Handle = (*((PVOID *)pIcaEndpoint));
  2564. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  2565. status = GetExceptionCode();
  2566. DBGPRINT(("DeviceQueryRemoteAddress: Exception 0x%x\n", status));
  2567. goto exitpt;
  2568. }
  2569. TRACE0(("DeviceOpenEndpoint: Fetching Handle 0x%x\n", Handle));
  2570. /*
  2571. * See if TERMDD knows about the handle
  2572. */
  2573. status = IcaReturnHandle( Handle, &pStackEndpoint, &Length );
  2574. if( !NT_SUCCESS(status) ) {
  2575. DBGPRINT(("DeviceQueryRemoteAddress: TERMDD handle 0x%x no good 0x%x\n", Handle, status));
  2576. status = STATUS_INVALID_PARAMETER_3;
  2577. goto exitpt;
  2578. }
  2579. if ( TDI_ADDRESS_TYPE_IP != pStackEndpoint->AddressType &&
  2580. TDI_ADDRESS_TYPE_IP6 != pStackEndpoint->AddressType )
  2581. {
  2582. status = STATUS_NOT_SUPPORTED;
  2583. goto exitpt;
  2584. }
  2585. if ( NULL == pStackEndpoint->pEndpoint )
  2586. {
  2587. status = STATUS_INVALID_PARAMETER_3; // remote address wasn't recorded
  2588. goto exitpt;
  2589. }
  2590. pRemoteAddress = pStackEndpoint->pEndpoint->pRemoteAddress;
  2591. ASSERT( 1 == pRemoteAddress->TAAddressCount );
  2592. pRemoteIP = pRemoteAddress->Address;
  2593. //
  2594. // check the size of the output including the protocol family
  2595. //
  2596. if ( pRemoteIP->AddressLength + sizeof( USHORT ) > OutputAddressSize )
  2597. {
  2598. status = STATUS_BUFFER_TOO_SMALL;
  2599. goto exitpt;
  2600. }
  2601. ASSERT( sizeof( TDI_ADDRESS_IP ) == pRemoteIP->AddressLength ||
  2602. sizeof( TDI_ADDRESS_IP6 ) == pRemoteIP->AddressLength );
  2603. ASSERT( TDI_ADDRESS_TYPE_IP == pRemoteIP->AddressType ||
  2604. TDI_ADDRESS_TYPE_IP6 == pRemoteIP->AddressType );
  2605. pOutput->sa_family = pRemoteIP->AddressType;
  2606. RtlCopyMemory( &pOutput->sa_data, &(pRemoteIP->Address), pRemoteIP->AddressLength );
  2607. *BytesReturned = sizeof( *pOutput );
  2608. status = STATUS_SUCCESS;
  2609. exitpt:
  2610. return status;
  2611. }
  2612. /*****************************************************************************
  2613. * _TdCancelReceiveQueue
  2614. *
  2615. * Cancel all of the I/O in the current Receive Queue
  2616. ****************************************************************************/
  2617. NTSTATUS _TdCancelReceiveQueue(PTD pTd, PTD_ENDPOINT pEndpoint, NTSTATUS CancelStatus)
  2618. {
  2619. PIRP Irp;
  2620. KIRQL OldIrql;
  2621. PLIST_ENTRY pEntry;
  2622. DBGPRINT(("_TdCancelReceiveQueue [%p]: Endpoint 0x%p\n", pTd, pEndpoint));
  2623. ExAcquireSpinLock( &pEndpoint->Spinlock, &OldIrql );
  2624. /*
  2625. * If we have any Receive Irp's, we are waiting for the
  2626. * indication handler to submit the I/O. Since the IRP
  2627. * is not submitted yet, we must cancel the IRP's.
  2628. */
  2629. while (!IsListEmpty(&pEndpoint->ReceiveQueue)) {
  2630. pEntry = RemoveHeadList( &pEndpoint->ReceiveQueue );
  2631. Irp = CONTAINING_RECORD( pEntry, IRP, Tail.Overlay.ListEntry );
  2632. TRACE0(("_TdCancelReceiveQueue: Cancel Receive Irp 0x%x on pEndpoint 0x%x\n",Irp,pEndpoint));
  2633. ExReleaseSpinLock( &pEndpoint->Spinlock, OldIrql );
  2634. Irp->IoStatus.Status = CancelStatus;
  2635. Irp->IoStatus.Information = 0;
  2636. // Since the IRP has not been submitted with IoCallDriver() yet,
  2637. // we must simulate.
  2638. IoSetNextIrpStackLocation(Irp);
  2639. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2640. ExAcquireSpinLock(&pEndpoint->Spinlock, &OldIrql);
  2641. }
  2642. ExReleaseSpinLock(&pEndpoint->Spinlock, OldIrql);
  2643. return STATUS_SUCCESS;
  2644. }