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.

1342 lines
41 KiB

  1. /*++
  2. Copyright (c) 1989-1999 Microsoft Corporation
  3. Module Name:
  4. disconn.c
  5. Abstract:
  6. This module contains the dispatch routines for AFD.
  7. Author:
  8. David Treadwell (davidtr) 31-Mar-1992
  9. Revision History:
  10. --*/
  11. #include "afdp.h"
  12. NTSTATUS
  13. AfdRestartAbort(
  14. IN PDEVICE_OBJECT DeviceObject,
  15. IN PIRP Irp,
  16. IN PVOID Context
  17. );
  18. NTSTATUS
  19. AfdRestartDisconnect(
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN PIRP Irp,
  22. IN PVOID Context
  23. );
  24. NTSTATUS
  25. AfdRestartDgDisconnect(
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp,
  28. IN PVOID Context
  29. );
  30. typedef struct _AFD_ABORT_CONTEXT {
  31. PAFD_CONNECTION Connection;
  32. } AFD_ABORT_CONTEXT, *PAFD_ABORT_CONTEXT;
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text( PAGEAFD, AfdPartialDisconnect )
  35. #pragma alloc_text( PAGEAFD, AfdDisconnectEventHandler )
  36. #pragma alloc_text( PAGEAFD, AfdBeginAbort )
  37. #pragma alloc_text( PAGEAFD, AfdRestartAbort )
  38. #pragma alloc_text( PAGEAFD, AfdBeginDisconnect )
  39. #pragma alloc_text( PAGEAFD, AfdRestartDisconnect )
  40. #endif
  41. NTSTATUS
  42. AfdPartialDisconnect(
  43. IN PFILE_OBJECT FileObject,
  44. IN ULONG IoctlCode,
  45. IN KPROCESSOR_MODE RequestorMode,
  46. IN PVOID InputBuffer,
  47. IN ULONG InputBufferLength,
  48. IN PVOID OutputBuffer,
  49. IN ULONG OutputBufferLength,
  50. OUT PUINT_PTR Information
  51. )
  52. {
  53. NTSTATUS status;
  54. AFD_LOCK_QUEUE_HANDLE lockHandle;
  55. PAFD_ENDPOINT endpoint;
  56. PAFD_CONNECTION connection;
  57. AFD_PARTIAL_DISCONNECT_INFO disconnectInfo;
  58. //
  59. // Nothing to return.
  60. //
  61. *Information = 0;
  62. status = STATUS_SUCCESS;
  63. connection = NULL;
  64. endpoint = FileObject->FsContext;
  65. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  66. #ifdef _WIN64
  67. {
  68. C_ASSERT (sizeof (AFD_PARTIAL_DISCONNECT_INFO)==sizeof (AFD_PARTIAL_DISCONNECT_INFO32));
  69. }
  70. #endif
  71. if (InputBufferLength<sizeof (disconnectInfo)) {
  72. status = STATUS_INVALID_PARAMETER;
  73. goto exit;
  74. }
  75. try {
  76. #ifdef _WIN64
  77. if (IoIs32bitProcess (NULL)) {
  78. //
  79. // Validate the input structure if it comes from the user mode
  80. // application
  81. //
  82. if (RequestorMode != KernelMode ) {
  83. ProbeForRead (InputBuffer,
  84. sizeof (disconnectInfo),
  85. PROBE_ALIGNMENT32 (AFD_PARTIAL_DISCONNECT_INFO32));
  86. }
  87. //
  88. // Make local copies of the embeded pointer and parameters
  89. // that we will be using more than once in case malicios
  90. // application attempts to change them while we are
  91. // validating
  92. //
  93. disconnectInfo.DisconnectMode = ((PAFD_PARTIAL_DISCONNECT_INFO32)InputBuffer)->DisconnectMode;
  94. disconnectInfo.Timeout = ((PAFD_PARTIAL_DISCONNECT_INFO32)InputBuffer)->Timeout;
  95. }
  96. else
  97. #endif _WIN64
  98. {
  99. //
  100. // Validate the input structure if it comes from the user mode
  101. // application
  102. //
  103. if (RequestorMode != KernelMode ) {
  104. ProbeForRead (InputBuffer,
  105. sizeof (disconnectInfo),
  106. PROBE_ALIGNMENT (AFD_PARTIAL_DISCONNECT_INFO));
  107. }
  108. //
  109. // Make local copies of the embeded pointer and parameters
  110. // that we will be using more than once in case malicios
  111. // application attempts to change them while we are
  112. // validating
  113. //
  114. disconnectInfo = *((PAFD_PARTIAL_DISCONNECT_INFO)InputBuffer);
  115. }
  116. } except( AFD_EXCEPTION_FILTER(&status) ) {
  117. goto exit;
  118. }
  119. IF_DEBUG(CONNECT) {
  120. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  121. "AfdPartialDisconnect: disconnecting endpoint %p, "
  122. "mode %lx, endp mode %lx\n",
  123. endpoint, disconnectInfo.DisconnectMode,
  124. endpoint->DisconnectMode ));
  125. }
  126. //
  127. // If this is a datagram endpoint, just remember how the endpoint
  128. // was shut down, don't actually do anything. Note that it is legal
  129. // to do a shutdown() on an unconnected datagram socket, so the
  130. // test that the socket must be connected is after this case.
  131. //
  132. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  133. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  134. if ( (disconnectInfo.DisconnectMode & AFD_ABORTIVE_DISCONNECT) != 0 ) {
  135. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
  136. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_SEND;
  137. endpoint->DisconnectMode |= AFD_ABORTIVE_DISCONNECT;
  138. }
  139. if ( (disconnectInfo.DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
  140. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
  141. }
  142. if ( (disconnectInfo.DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) != 0 ) {
  143. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_SEND;
  144. }
  145. if (AFD_START_STATE_CHANGE (endpoint, AfdEndpointStateBound)) {
  146. if ( (disconnectInfo.DisconnectMode & AFD_UNCONNECT_DATAGRAM) != 0 &&
  147. endpoint->State==AfdEndpointStateConnected) {
  148. if( endpoint->Common.Datagram.RemoteAddress != NULL ) {
  149. AFD_RETURN_REMOTE_ADDRESS(
  150. endpoint->Common.Datagram.RemoteAddress,
  151. endpoint->Common.Datagram.RemoteAddressLength
  152. );
  153. }
  154. endpoint->Common.Datagram.RemoteAddress = NULL;
  155. endpoint->Common.Datagram.RemoteAddressLength = 0;
  156. //
  157. // Even if disconnect fails, we consider
  158. // ourselves not connected anymore
  159. //
  160. endpoint->State = AfdEndpointStateBound;
  161. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  162. if (IS_TDI_DGRAM_CONNECTION(endpoint)) {
  163. PIRP irp;
  164. KEVENT event;
  165. IO_STATUS_BLOCK ioStatusBlock;
  166. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  167. irp = TdiBuildInternalDeviceControlIrp (
  168. TDI_DISCONNECT,
  169. endpoint->AddressDeviceObject,
  170. endpoint->AddressFileObject,
  171. &event,
  172. &ioStatusBlock
  173. );
  174. if ( irp != NULL ) {
  175. TdiBuildDisconnect(
  176. irp,
  177. endpoint->AddressDeviceObject,
  178. endpoint->AddressFileObject,
  179. NULL,
  180. NULL,
  181. &disconnectInfo.Timeout,
  182. (disconnectInfo.DisconnectMode & AFD_ABORTIVE_DISCONNECT)
  183. ? TDI_DISCONNECT_ABORT
  184. : TDI_DISCONNECT_RELEASE,
  185. NULL,
  186. NULL
  187. );
  188. status = IoCallDriver( endpoint->AddressDeviceObject, irp );
  189. if ( status == STATUS_PENDING ) {
  190. status = KeWaitForSingleObject( (PVOID)&event, Executive, KernelMode, FALSE, NULL );
  191. ASSERT (status==STATUS_SUCCESS);
  192. }
  193. else {
  194. //
  195. // The IRP must have been completed then and event set.
  196. //
  197. ASSERT (NT_ERROR (status) || KeReadStateEvent (&event));
  198. }
  199. }
  200. else {
  201. status = STATUS_INSUFFICIENT_RESOURCES;
  202. }
  203. }
  204. }
  205. else {
  206. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  207. status = STATUS_SUCCESS;
  208. }
  209. AFD_END_STATE_CHANGE (endpoint);
  210. }
  211. else {
  212. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  213. status = STATUS_INVALID_PARAMETER;
  214. }
  215. goto exit;
  216. }
  217. //
  218. // Make sure that the endpoint is in the correct state.
  219. //
  220. if ( (endpoint->Type & AfdBlockTypeVcConnecting)!=AfdBlockTypeVcConnecting ||
  221. endpoint->Listening ||
  222. endpoint->afdC_Root ||
  223. endpoint->State != AfdEndpointStateConnected ||
  224. ((connection=AfdGetConnectionReferenceFromEndpoint (endpoint))==NULL)) {
  225. status = STATUS_INVALID_PARAMETER;
  226. goto exit;
  227. }
  228. ASSERT( connection->Type == AfdBlockTypeConnection );
  229. //
  230. // If we're doing an abortive disconnect, remember that the receive
  231. // side is shut down and issue a disorderly release.
  232. //
  233. if ( (disconnectInfo.DisconnectMode & AFD_ABORTIVE_DISCONNECT) != 0 ) {
  234. IF_DEBUG(CONNECT) {
  235. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  236. "AfdPartialDisconnect: abortively disconnecting endp %p\n",
  237. endpoint ));
  238. }
  239. status = AfdBeginAbort( connection );
  240. if ( status == STATUS_PENDING ) {
  241. status = STATUS_SUCCESS;
  242. }
  243. goto exit;
  244. }
  245. //
  246. // If the receive side of the connection is being shut down,
  247. // remember the fact in the endpoint. If there is pending data on
  248. // the VC, do a disorderly release on the endpoint. If the receive
  249. // side has already been shut down, do nothing.
  250. //
  251. if ( (disconnectInfo.DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 &&
  252. (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) == 0 ) {
  253. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  254. //
  255. // Determine whether there is pending data.
  256. //
  257. if ( IS_DATA_ON_CONNECTION( connection ) ||
  258. IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
  259. //
  260. // There is unreceived data. Abort the connection.
  261. //
  262. IF_DEBUG(CONNECT) {
  263. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  264. "AfdPartialDisconnect: unreceived data on endp %p, conn %p, aborting.\n",
  265. endpoint, connection ));
  266. }
  267. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  268. (VOID)AfdBeginAbort( connection );
  269. status = STATUS_SUCCESS;
  270. goto exit;
  271. } else {
  272. IF_DEBUG(CONNECT) {
  273. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  274. "AfdPartialDisconnect: disconnecting recv for endp %p\n",
  275. endpoint ));
  276. }
  277. //
  278. // Remember that the receive side is shut down. This will cause
  279. // the receive indication handlers to dump any data that
  280. // arrived.
  281. //
  282. // !!! This is a minor violation of RFC1122 4.2.2.13. We
  283. // should really do an abortive disconnect if data
  284. // arrives after a receive shutdown.
  285. //
  286. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
  287. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  288. }
  289. }
  290. //
  291. // If the send side is being shut down, remember it in the endpoint
  292. // and pass the request on to the TDI provider for a graceful
  293. // disconnect. If the send side is already shut down, do nothing here.
  294. //
  295. if ( (disconnectInfo.DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) != 0 &&
  296. (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) == 0 ) {
  297. status = AfdBeginDisconnect( endpoint, &disconnectInfo.Timeout, NULL );
  298. if ( !NT_SUCCESS(status) ) {
  299. goto exit;
  300. }
  301. if ( status == STATUS_PENDING ) {
  302. status = STATUS_SUCCESS;
  303. }
  304. }
  305. status = STATUS_SUCCESS;
  306. exit:
  307. if (connection!=NULL) {
  308. DEREFERENCE_CONNECTION (connection);
  309. }
  310. return status;
  311. } // AfdPartialDisconnect
  312. NTSTATUS
  313. AfdDisconnectEventHandler(
  314. IN PVOID TdiEventContext,
  315. IN CONNECTION_CONTEXT ConnectionContext,
  316. IN int DisconnectDataLength,
  317. IN PVOID DisconnectData,
  318. IN int DisconnectInformationLength,
  319. IN PVOID DisconnectInformation,
  320. IN ULONG DisconnectFlags
  321. )
  322. {
  323. PAFD_CONNECTION connection = ConnectionContext;
  324. PAFD_ENDPOINT endpoint;
  325. AFD_LOCK_QUEUE_HANDLE lockHandle;
  326. NTSTATUS status;
  327. BOOLEAN result;
  328. ASSERT( connection != NULL );
  329. //
  330. // Reference the connection object so that it does not go away while
  331. // we're processing it inside this function. Without this
  332. // reference, the user application could close the endpoint object,
  333. // the connection reference count could go to zero, and the
  334. // AfdDeleteConnectedReference call at the end of this function
  335. // could cause a crash if the AFD connection object has been
  336. // completely cleaned up.
  337. //
  338. CHECK_REFERENCE_CONNECTION( connection, result);
  339. if (!result) {
  340. return STATUS_SUCCESS;
  341. }
  342. ASSERT( connection->Type == AfdBlockTypeConnection );
  343. endpoint = connection->Endpoint;
  344. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  345. endpoint->Type == AfdBlockTypeVcListening ||
  346. endpoint->Type == AfdBlockTypeVcBoth);
  347. IF_DEBUG(CONNECT) {
  348. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  349. "AfdDisconnectEventHandler called for endpoint %p, connection %p\n",
  350. connection->Endpoint, connection ));
  351. }
  352. UPDATE_CONN2( connection, "DisconnectEvent, flags: %lx", DisconnectFlags );
  353. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  354. //
  355. // Check if connection was accepted and use accept endpoint instead
  356. // of the listening. Note that accept cannot happen while we are
  357. // holding listening endpoint spinlock, nor can endpoint change after
  358. // the accept and while connection is referenced, so it is safe to
  359. // release listening spinlock if we discover that endpoint was accepted.
  360. //
  361. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  362. && (connection->Endpoint != endpoint)) {
  363. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  364. endpoint = connection->Endpoint;
  365. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  366. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  367. ASSERT( IS_VC_ENDPOINT (endpoint) );
  368. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  369. }
  370. //
  371. // Set up in the connection the fact that the remote side has
  372. // disconnected or aborted.
  373. //
  374. if ( (DisconnectFlags & TDI_DISCONNECT_ABORT) != 0 ) {
  375. connection->AbortIndicated = TRUE;
  376. status = STATUS_REMOTE_DISCONNECT;
  377. AfdRecordAbortiveDisconnectIndications();
  378. } else {
  379. connection->DisconnectIndicated = TRUE;
  380. if ( !IS_MESSAGE_ENDPOINT(endpoint) ) {
  381. status = STATUS_SUCCESS;
  382. } else {
  383. status = STATUS_GRACEFUL_DISCONNECT;
  384. }
  385. AfdRecordGracefulDisconnectIndications();
  386. }
  387. if (connection->State==AfdConnectionStateConnected) {
  388. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  389. if ( (DisconnectFlags & TDI_DISCONNECT_ABORT) != 0 ) {
  390. AfdIndicateEventSelectEvent(
  391. endpoint,
  392. AFD_POLL_ABORT,
  393. STATUS_SUCCESS
  394. );
  395. } else {
  396. AfdIndicateEventSelectEvent(
  397. endpoint,
  398. AFD_POLL_DISCONNECT,
  399. STATUS_SUCCESS
  400. );
  401. }
  402. }
  403. //
  404. // If this is a nonbufferring transport, complete any pended receives.
  405. //
  406. if ( !connection->TdiBufferring ) {
  407. //
  408. // If this is an abort indication, complete all pended sends and
  409. // discard any bufferred receive data.
  410. //
  411. if ( connection->AbortIndicated ) {
  412. connection->VcBufferredReceiveBytes = 0;
  413. connection->VcBufferredReceiveCount = 0;
  414. connection->VcBufferredExpeditedBytes = 0;
  415. connection->VcBufferredExpeditedCount = 0;
  416. connection->VcReceiveBytesInTransport = 0;
  417. while ( !IsListEmpty( &connection->VcReceiveBufferListHead ) ) {
  418. PAFD_BUFFER_HEADER afdBuffer;
  419. PLIST_ENTRY listEntry;
  420. listEntry = RemoveHeadList( &connection->VcReceiveBufferListHead );
  421. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  422. DEBUG afdBuffer->BufferListEntry.Flink = NULL;
  423. if (afdBuffer->RefCount==1 || // Can't change once off the list
  424. InterlockedDecrement (&afdBuffer->RefCount)==0) {
  425. afdBuffer->ExpeditedData = FALSE;
  426. AfdReturnBuffer( afdBuffer, connection->OwningProcess);
  427. }
  428. }
  429. //
  430. // Check for the most typical case where we do not
  431. // have anything to complete and thus do not need to
  432. // make a call and take/release the spinlock.
  433. //
  434. if ( (IsListEmpty (&connection->VcSendIrpListHead) &&
  435. IsListEmpty (&connection->VcReceiveIrpListHead)) ||
  436. ((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening) ) {
  437. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  438. }
  439. else {
  440. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  441. AfdCompleteIrpList(
  442. &connection->VcSendIrpListHead,
  443. endpoint,
  444. status,
  445. AfdCleanupSendIrp
  446. );
  447. AfdCompleteIrpList(
  448. &connection->VcReceiveIrpListHead,
  449. endpoint,
  450. status,
  451. NULL
  452. );
  453. }
  454. }
  455. else {
  456. //
  457. // Check for the most typical case where we do not
  458. // have anything to complete and thus do not need to
  459. // make a call and take/release the spinlock.
  460. //
  461. if ( IsListEmpty (&connection->VcReceiveIrpListHead) ||
  462. ((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)) {
  463. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  464. }
  465. else {
  466. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  467. AfdCompleteIrpList(
  468. &connection->VcReceiveIrpListHead,
  469. endpoint,
  470. status,
  471. NULL
  472. );
  473. }
  474. }
  475. }
  476. else {
  477. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  478. }
  479. //
  480. // If we got disconnect data or options, save it.
  481. //
  482. if( ( DisconnectData != NULL && DisconnectDataLength > 0 ) ||
  483. ( DisconnectInformation != NULL && DisconnectInformationLength > 0 ) ) {
  484. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  485. //
  486. // Check if connection was accepted and use accept endpoint instead
  487. // of the listening. Note that accept cannot happen while we are
  488. // holding listening endpoint spinlock, nor can endpoint change after
  489. // the accept and while connection is referenced, so it is safe to
  490. // release listening spinlock if we discover that endpoint was accepted.
  491. //
  492. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  493. && (connection->Endpoint != endpoint)) {
  494. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  495. endpoint = connection->Endpoint;
  496. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  497. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  498. ASSERT( IS_VC_ENDPOINT (endpoint) );
  499. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  500. }
  501. if( DisconnectData != NULL && DisconnectDataLength > 0 ) {
  502. status = AfdSaveReceivedConnectData(
  503. &connection->ConnectDataBuffers,
  504. IOCTL_AFD_SET_DISCONNECT_DATA,
  505. DisconnectData,
  506. DisconnectDataLength
  507. );
  508. if( !NT_SUCCESS(status) ) {
  509. //
  510. // We hit an allocation failure, but press on regardless.
  511. //
  512. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  513. "AfdSaveReceivedConnectData failed: %08lx\n",
  514. status
  515. ));
  516. }
  517. }
  518. if( DisconnectInformation != NULL && DisconnectInformationLength > 0 ) {
  519. status = AfdSaveReceivedConnectData(
  520. &connection->ConnectDataBuffers,
  521. IOCTL_AFD_SET_DISCONNECT_DATA,
  522. DisconnectInformation,
  523. DisconnectInformationLength
  524. );
  525. if( !NT_SUCCESS(status) ) {
  526. //
  527. // We hit an allocation failure, but press on regardless.
  528. //
  529. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  530. "AfdSaveReceivedConnectData failed: %08lx\n",
  531. status
  532. ));
  533. }
  534. }
  535. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  536. }
  537. //
  538. // Call AfdIndicatePollEvent in case anyone is polling on this
  539. // connection getting disconnected or aborted.
  540. //
  541. // Make sure the connection was accepted/connected
  542. // in order not to signal on listening endpoint
  543. //
  544. if (connection->State==AfdConnectionStateConnected) {
  545. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  546. if ( (DisconnectFlags & TDI_DISCONNECT_ABORT) != 0 ) {
  547. AfdIndicatePollEvent(
  548. endpoint,
  549. AFD_POLL_ABORT,
  550. STATUS_SUCCESS
  551. );
  552. } else {
  553. AfdIndicatePollEvent(
  554. endpoint,
  555. AFD_POLL_DISCONNECT,
  556. STATUS_SUCCESS
  557. );
  558. }
  559. }
  560. //
  561. // Remove the connected reference on the connection object. We must
  562. // do this AFTER setting up the flag which remembers the disconnect
  563. // type that occurred. We must also do this AFTER we have finished
  564. // handling everything in the endpoint, since the endpoint structure
  565. // may no longer have any information about the connection object if
  566. // a transmit request with AFD_TF_REUSE_SOCKET happenned on it.
  567. //
  568. AfdDeleteConnectedReference( connection, FALSE );
  569. //
  570. // Dereference the connection from the reference added above.
  571. //
  572. DEREFERENCE_CONNECTION( connection );
  573. return STATUS_SUCCESS;
  574. } // AfdDisconnectEventHandler
  575. NTSTATUS
  576. AfdBeginAbort(
  577. IN PAFD_CONNECTION Connection
  578. )
  579. {
  580. PAFD_ENDPOINT endpoint = Connection->Endpoint;
  581. PIRP irp;
  582. PFILE_OBJECT fileObject;
  583. PDEVICE_OBJECT deviceObject;
  584. AFD_LOCK_QUEUE_HANDLE lockHandle;
  585. IF_DEBUG(CONNECT) {
  586. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  587. "AfdBeginAbort: aborting on endpoint %p\n",
  588. endpoint ));
  589. }
  590. UPDATE_CONN( Connection );
  591. //
  592. // Build an IRP to reset the connection. First get the address
  593. // of the target device object.
  594. //
  595. ASSERT( Connection->Type == AfdBlockTypeConnection );
  596. fileObject = Connection->FileObject;
  597. ASSERT( fileObject != NULL );
  598. deviceObject = IoGetRelatedDeviceObject( fileObject );
  599. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  600. //
  601. // Check if connection was accepted and use accept endpoint instead
  602. // of the listening. Note that accept cannot happen while we are
  603. // holding listening endpoint spinlock, nor can endpoint change after
  604. // the accept and while connection is referenced, so it is safe to
  605. // release listening spinlock if we discover that endpoint was accepted.
  606. //
  607. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  608. && (Connection->Endpoint != endpoint)) {
  609. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  610. endpoint = Connection->Endpoint;
  611. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  612. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  613. ASSERT( IS_VC_ENDPOINT (endpoint) );
  614. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  615. }
  616. //
  617. // If the endpoint has already been abortively disconnected,
  618. // or if has been gracefully disconnected and the transport
  619. // does not support orderly (i.e. two-phase) release, then just
  620. // succeed this request.
  621. //
  622. // Note that, since the abort completion routine (AfdRestartAbort)
  623. // will not be called, we must delete the connected reference
  624. // ourselves and complete outstanding send IRPs if ANY.
  625. //
  626. if ( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) != 0 ||
  627. Connection->AbortIndicated ||
  628. (Connection->DisconnectIndicated &&
  629. !IS_TDI_ORDERLY_RELEASE(endpoint) )) {
  630. if ( !IS_TDI_BUFFERRING(endpoint) &&
  631. endpoint->Type != AfdBlockTypeVcListening ) {
  632. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  633. AfdCompleteIrpList(
  634. &Connection->VcSendIrpListHead,
  635. endpoint,
  636. STATUS_LOCAL_DISCONNECT,
  637. AfdCleanupSendIrp
  638. );
  639. }
  640. else {
  641. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  642. }
  643. AfdDeleteConnectedReference( Connection, FALSE );
  644. return STATUS_SUCCESS;
  645. }
  646. //
  647. // Remember that the connection has been aborted.
  648. //
  649. if ( (endpoint->Type & AfdBlockTypeVcListening)!= AfdBlockTypeVcListening ) {
  650. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
  651. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_SEND;
  652. endpoint->DisconnectMode |= AFD_ABORTIVE_DISCONNECT;
  653. }
  654. Connection->AbortIndicated = TRUE;
  655. //
  656. // Set the BytesTaken fields equal to the BytesIndicated fields so
  657. // that no more AFD_POLL_RECEIVE or AFD_POLL_RECEIVE_EXPEDITED
  658. // events get completed.
  659. //
  660. if ( IS_TDI_BUFFERRING(endpoint) ) {
  661. Connection->Common.Bufferring.ReceiveBytesTaken =
  662. Connection->Common.Bufferring.ReceiveBytesIndicated;
  663. Connection->Common.Bufferring.ReceiveExpeditedBytesTaken =
  664. Connection->Common.Bufferring.ReceiveExpeditedBytesIndicated;
  665. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  666. } else if ( endpoint->Type != AfdBlockTypeVcListening ) {
  667. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  668. //
  669. // Complete all of the connection's pended sends and receives.
  670. //
  671. AfdCompleteIrpList(
  672. &Connection->VcReceiveIrpListHead,
  673. endpoint,
  674. STATUS_LOCAL_DISCONNECT,
  675. NULL
  676. );
  677. AfdCompleteIrpList(
  678. &Connection->VcSendIrpListHead,
  679. endpoint,
  680. STATUS_LOCAL_DISCONNECT,
  681. AfdCleanupSendIrp
  682. );
  683. } else {
  684. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  685. }
  686. //
  687. // Allocate an IRP. The stack size is one higher than that of the
  688. // target device, to allow for the caller's completion routine.
  689. //
  690. irp = IoAllocateIrp( (CCHAR)(deviceObject->StackSize), FALSE );
  691. if ( irp == NULL ) {
  692. return STATUS_INSUFFICIENT_RESOURCES;
  693. }
  694. //
  695. // Initialize the IRP for an abortive disconnect.
  696. //
  697. irp->MdlAddress = NULL;
  698. irp->Flags = 0;
  699. irp->RequestorMode = KernelMode;
  700. irp->PendingReturned = FALSE;
  701. irp->UserIosb = NULL;
  702. irp->UserEvent = NULL;
  703. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  704. irp->AssociatedIrp.SystemBuffer = NULL;
  705. irp->UserBuffer = NULL;
  706. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  707. irp->Tail.Overlay.OriginalFileObject = fileObject;
  708. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  709. TdiBuildDisconnect(
  710. irp,
  711. deviceObject,
  712. fileObject,
  713. AfdRestartAbort,
  714. Connection,
  715. NULL,
  716. TDI_DISCONNECT_ABORT,
  717. NULL,
  718. NULL
  719. );
  720. //
  721. // Reference the connection object so that it does not go away
  722. // until the abort completes.
  723. //
  724. REFERENCE_CONNECTION( Connection );
  725. AfdRecordAbortiveDisconnectsInitiated();
  726. //
  727. // Pass the request to the transport provider.
  728. //
  729. return IoCallDriver( deviceObject, irp );
  730. } // AfdBeginAbort
  731. NTSTATUS
  732. AfdRestartAbort(
  733. IN PDEVICE_OBJECT DeviceObject,
  734. IN PIRP Irp,
  735. IN PVOID Context
  736. )
  737. {
  738. PAFD_CONNECTION connection;
  739. PAFD_ENDPOINT endpoint;
  740. connection = Context;
  741. ASSERT( connection != NULL );
  742. ASSERT( connection->Type == AfdBlockTypeConnection );
  743. IF_DEBUG(CONNECT) {
  744. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  745. "AfdRestartAbort: abort completed, status = %X, endpoint = %p\n",
  746. Irp->IoStatus.Status,
  747. connection->Endpoint
  748. ));
  749. }
  750. endpoint = connection->Endpoint;
  751. UPDATE_CONN2 ( connection, "Restart abort, status: %lx", Irp->IoStatus.Status);
  752. AfdRecordAbortiveDisconnectsCompleted();
  753. //
  754. // Remember that the connection has been aborted, and indicate if
  755. // necessary.
  756. //
  757. if( connection->State==AfdConnectionStateConnected ) {
  758. AFD_LOCK_QUEUE_HANDLE lockHandle;
  759. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  760. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  761. AfdIndicateEventSelectEvent (
  762. endpoint,
  763. AFD_POLL_ABORT,
  764. STATUS_SUCCESS
  765. );
  766. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  767. AfdIndicatePollEvent(
  768. endpoint,
  769. AFD_POLL_ABORT,
  770. STATUS_SUCCESS
  771. );
  772. }
  773. if( !connection->TdiBufferring ) {
  774. //
  775. // Complete all of the connection's pended sends and receives.
  776. //
  777. AfdCompleteIrpList(
  778. &connection->VcReceiveIrpListHead,
  779. endpoint,
  780. STATUS_LOCAL_DISCONNECT,
  781. NULL
  782. );
  783. AfdCompleteIrpList(
  784. &connection->VcSendIrpListHead,
  785. endpoint,
  786. STATUS_LOCAL_DISCONNECT,
  787. AfdCleanupSendIrp
  788. );
  789. }
  790. //
  791. // Remove the connected reference from the connection, since we
  792. // know that the connection will not be active any longer.
  793. //
  794. AfdDeleteConnectedReference( connection, FALSE );
  795. //
  796. // Dereference the AFD connection object.
  797. //
  798. DEREFERENCE_CONNECTION( connection );
  799. //
  800. // Free the IRP now since it is no longer needed.
  801. //
  802. IoFreeIrp( Irp );
  803. //
  804. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  805. // will stop working on the IRP.
  806. //
  807. return STATUS_MORE_PROCESSING_REQUIRED;
  808. } // AfdRestartAbort
  809. NTSTATUS
  810. AfdBeginDisconnect(
  811. IN PAFD_ENDPOINT Endpoint,
  812. IN PLARGE_INTEGER Timeout OPTIONAL,
  813. OUT PIRP *DisconnectIrp OPTIONAL
  814. )
  815. {
  816. PTDI_CONNECTION_INFORMATION requestConnectionInformation = NULL;
  817. PTDI_CONNECTION_INFORMATION returnConnectionInformation = NULL;
  818. PAFD_CONNECTION connection;
  819. AFD_LOCK_QUEUE_HANDLE lockHandle;
  820. PFILE_OBJECT fileObject;
  821. PDEVICE_OBJECT deviceObject;
  822. PAFD_DISCONNECT_CONTEXT disconnectContext;
  823. PIRP irp;
  824. if ( DisconnectIrp != NULL ) {
  825. *DisconnectIrp = NULL;
  826. }
  827. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  828. ASSERT( Endpoint->Type == AfdBlockTypeVcConnecting );
  829. connection = AFD_CONNECTION_FROM_ENDPOINT( Endpoint );
  830. if (connection==NULL) {
  831. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  832. return STATUS_SUCCESS;
  833. }
  834. ASSERT( connection->Type == AfdBlockTypeConnection );
  835. UPDATE_CONN( connection );
  836. //
  837. // If the endpoint has already been abortively disconnected,
  838. // just succeed this request.
  839. //
  840. if ( (Endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) != 0 ||
  841. connection->AbortIndicated ) {
  842. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  843. return STATUS_SUCCESS;
  844. }
  845. //
  846. // If this connection has already been disconnected, just succeed.
  847. //
  848. if ( (Endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) != 0 ) {
  849. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  850. return STATUS_SUCCESS;
  851. }
  852. fileObject = connection->FileObject;
  853. ASSERT( fileObject != NULL );
  854. deviceObject = IoGetRelatedDeviceObject( fileObject );
  855. //
  856. // Allocate and initialize a disconnect IRP.
  857. //
  858. irp = IoAllocateIrp( (CCHAR)(deviceObject->StackSize), FALSE );
  859. if ( irp == NULL ) {
  860. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  861. return STATUS_INSUFFICIENT_RESOURCES;
  862. }
  863. //
  864. // Initialize the IRP.
  865. //
  866. irp->MdlAddress = NULL;
  867. irp->Flags = 0;
  868. irp->RequestorMode = KernelMode;
  869. irp->PendingReturned = FALSE;
  870. irp->UserIosb = NULL;
  871. irp->UserEvent = NULL;
  872. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  873. irp->AssociatedIrp.SystemBuffer = NULL;
  874. irp->UserBuffer = NULL;
  875. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  876. irp->Tail.Overlay.OriginalFileObject = fileObject;
  877. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  878. //
  879. // Use the disconnect context space in the connection structure.
  880. //
  881. disconnectContext = &connection->DisconnectContext;
  882. disconnectContext->Irp = irp;
  883. //
  884. // Remember that the send side has been disconnected.
  885. //
  886. Endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_SEND;
  887. //
  888. // If there are disconnect data buffers, allocate request
  889. // and return connection information structures and copy over
  890. // pointers to the structures.
  891. //
  892. if ( connection->ConnectDataBuffers != NULL ) {
  893. requestConnectionInformation = &connection->ConnectDataBuffers->RequestConnectionInfo;
  894. RtlZeroMemory (requestConnectionInformation, sizeof (*requestConnectionInformation));
  895. requestConnectionInformation->UserData =
  896. connection->ConnectDataBuffers->SendDisconnectData.Buffer;
  897. requestConnectionInformation->UserDataLength =
  898. connection->ConnectDataBuffers->SendDisconnectData.BufferLength;
  899. requestConnectionInformation->Options =
  900. connection->ConnectDataBuffers->SendDisconnectOptions.Buffer;
  901. requestConnectionInformation->OptionsLength =
  902. connection->ConnectDataBuffers->SendDisconnectOptions.BufferLength;
  903. returnConnectionInformation = &connection->ConnectDataBuffers->ReturnConnectionInfo;
  904. RtlZeroMemory (returnConnectionInformation, sizeof (*returnConnectionInformation));
  905. returnConnectionInformation->UserData =
  906. connection->ConnectDataBuffers->ReceiveDisconnectData.Buffer;
  907. returnConnectionInformation->UserDataLength =
  908. connection->ConnectDataBuffers->ReceiveDisconnectData.BufferLength;
  909. returnConnectionInformation->Options =
  910. connection->ConnectDataBuffers->ReceiveDisconnectOptions.Buffer;
  911. returnConnectionInformation->OptionsLength =
  912. connection->ConnectDataBuffers->ReceiveDisconnectOptions.BufferLength;
  913. }
  914. //
  915. // Set up the timeout for the disconnect.
  916. //
  917. if (Timeout==NULL) {
  918. disconnectContext->Timeout.QuadPart = -1;
  919. }
  920. else {
  921. disconnectContext->Timeout.QuadPart = Timeout->QuadPart;
  922. }
  923. //
  924. // Build a disconnect Irp to pass to the TDI provider.
  925. //
  926. TdiBuildDisconnect(
  927. irp,
  928. connection->DeviceObject,
  929. connection->FileObject,
  930. AfdRestartDisconnect,
  931. connection,
  932. &disconnectContext->Timeout,
  933. TDI_DISCONNECT_RELEASE,
  934. requestConnectionInformation,
  935. returnConnectionInformation
  936. );
  937. IF_DEBUG(CONNECT) {
  938. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  939. "AfdBeginDisconnect: disconnecting endpoint %p\n",
  940. Endpoint ));
  941. }
  942. //
  943. // Reference the connection so the space stays
  944. // allocated until the disconnect completes.
  945. //
  946. REFERENCE_CONNECTION( connection );
  947. //
  948. // If there are still outstanding sends and this is a nonbufferring
  949. // TDI transport which does not support orderly release, pend the
  950. // IRP until all the sends have completed.
  951. //
  952. if ( !IS_TDI_ORDERLY_RELEASE(Endpoint) &&
  953. !IS_TDI_BUFFERRING(Endpoint) && connection->VcBufferredSendCount != 0 ) {
  954. ASSERT( connection->VcDisconnectIrp == NULL );
  955. connection->VcDisconnectIrp = irp;
  956. connection->SpecialCondition = TRUE;
  957. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  958. return STATUS_PENDING;
  959. }
  960. AfdRecordGracefulDisconnectsInitiated();
  961. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  962. //
  963. // Pass the disconnect request on to the TDI provider.
  964. //
  965. if ( DisconnectIrp == NULL ) {
  966. return IoCallDriver( connection->DeviceObject, irp );
  967. } else {
  968. *DisconnectIrp = irp;
  969. return STATUS_SUCCESS;
  970. }
  971. } // AfdBeginDisconnect
  972. NTSTATUS
  973. AfdRestartDisconnect(
  974. IN PDEVICE_OBJECT DeviceObject,
  975. IN PIRP Irp,
  976. IN PVOID Context
  977. )
  978. {
  979. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  980. PAFD_CONNECTION connection=Context;
  981. AFD_LOCK_QUEUE_HANDLE lockHandle;
  982. UPDATE_CONN2( connection, "Restart disconnect, status: %lx", Irp->IoStatus.Status );
  983. AfdRecordGracefulDisconnectsCompleted();
  984. ASSERT( connection != NULL );
  985. ASSERT( connection->Type == AfdBlockTypeConnection );
  986. IF_DEBUG(CONNECT) {
  987. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  988. "AfdRestartDisconnect: disconnect completed, status = %X, endpoint = %p\n",
  989. Irp->IoStatus.Status, connection->Endpoint ));
  990. }
  991. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  992. if (connection->ConnectDataBuffers!=NULL) {
  993. PAFD_ENDPOINT endpoint = connection->Endpoint;
  994. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  995. //
  996. // Check if connection was accepted and use accept endpoint instead
  997. // of the listening. Note that accept cannot happen while we are
  998. // holding listening endpoint spinlock, nor can endpoint change after
  999. // the accept and while connection is referenced, so it is safe to
  1000. // release listening spinlock if we discover that endpoint was accepted.
  1001. //
  1002. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  1003. && (connection->Endpoint != endpoint)) {
  1004. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1005. endpoint = connection->Endpoint;
  1006. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  1007. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1008. ASSERT( IS_VC_ENDPOINT (endpoint) );
  1009. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1010. }
  1011. connectDataBuffers = connection->ConnectDataBuffers;
  1012. if (connectDataBuffers!=NULL) {
  1013. if( connectDataBuffers->ReturnConnectionInfo.UserData != NULL &&
  1014. connectDataBuffers->ReturnConnectionInfo.UserDataLength > 0 ) {
  1015. NTSTATUS status;
  1016. status = AfdSaveReceivedConnectData(
  1017. &connectDataBuffers,
  1018. IOCTL_AFD_SET_DISCONNECT_DATA,
  1019. connectDataBuffers->ReturnConnectionInfo.UserData,
  1020. connectDataBuffers->ReturnConnectionInfo.UserDataLength
  1021. );
  1022. ASSERT (NT_SUCCESS(status));
  1023. }
  1024. if( connectDataBuffers->ReturnConnectionInfo.Options != NULL &&
  1025. connectDataBuffers->ReturnConnectionInfo.OptionsLength > 0 ) {
  1026. NTSTATUS status;
  1027. status = AfdSaveReceivedConnectData(
  1028. &connectDataBuffers,
  1029. IOCTL_AFD_SET_DISCONNECT_OPTIONS,
  1030. connectDataBuffers->ReturnConnectionInfo.Options,
  1031. connectDataBuffers->ReturnConnectionInfo.OptionsLength
  1032. );
  1033. ASSERT (NT_SUCCESS(status));
  1034. }
  1035. }
  1036. AfdReleaseSpinLock (&connection->Endpoint->SpinLock, &lockHandle);
  1037. }
  1038. }
  1039. else {
  1040. AfdBeginAbort (connection);
  1041. }
  1042. DEREFERENCE_CONNECTION( connection );
  1043. //
  1044. // Free the IRP and return a status code so that the IO system will
  1045. // stop working on the IRP.
  1046. //
  1047. IoFreeIrp( Irp );
  1048. return STATUS_MORE_PROCESSING_REQUIRED;
  1049. } // AfdRestartDisconnect