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

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