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.

1357 lines
37 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blkconn.c
  5. Abstract:
  6. This module implements routines for managing connection blocks.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 4-Oct-1989
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "blkconn.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKCONN
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvAllocateConnection )
  17. #pragma alloc_text( PAGE, SrvCloseConnectionsFromClient )
  18. #if !defined(DBG) || DBG == 0
  19. #pragma alloc_text( PAGE, SrvFreeConnection )
  20. #endif
  21. #endif
  22. #if 0
  23. NOT PAGEABLE -- SrvCloseConnection
  24. NOT PAGEABLE -- SrvCloseFreeConnection
  25. NOT PAGEABLE -- SrvDereferenceConnection
  26. NOT PAGEABLE -- SrvQueryConnections
  27. #endif
  28. CHAR DisconnectReasonText[((USHORT)DisconnectReasons)+1][32] = {
  29. "Idle Connection",
  30. "Endpoint Closing",
  31. "2nd Sess Setup on Conn",
  32. "Transport Issued Disconnect",
  33. "Session Deleted",
  34. "Bad SMB Packet",
  35. "Suspected DOS",
  36. "Cancelled/Failed Receive",
  37. "Stale IPX Conn",
  38. "Unknown"
  39. };
  40. VOID
  41. SrvAllocateConnection (
  42. OUT PCONNECTION *Connection
  43. )
  44. /*++
  45. Routine Description:
  46. This function allocates a Connection Block from the system nonpaged
  47. pool.
  48. Arguments:
  49. Connection - Returns a pointer to the connection block, or NULL if
  50. no pool was available.
  51. Return Value:
  52. None.
  53. --*/
  54. {
  55. PCONNECTION connection;
  56. ULONG i;
  57. PPAGED_CONNECTION pagedConnection;
  58. PAGED_CODE( );
  59. //
  60. // Attempt to allocate from nonpaged pool.
  61. //
  62. connection = ALLOCATE_NONPAGED_POOL( sizeof(CONNECTION), BlockTypeConnection );
  63. *Connection = connection;
  64. if ( connection == NULL ) {
  65. INTERNAL_ERROR(
  66. ERROR_LEVEL_EXPECTED,
  67. "SrvAllocateConnection: Unable to allocate %d bytes from"
  68. "nonpaged pool",
  69. sizeof( CONNECTION ),
  70. NULL
  71. );
  72. return;
  73. }
  74. RtlZeroMemory( connection, sizeof(CONNECTION) );
  75. pagedConnection = ALLOCATE_HEAP_COLD(
  76. sizeof(PAGED_CONNECTION),
  77. BlockTypePagedConnection );
  78. if ( pagedConnection == NULL ) {
  79. INTERNAL_ERROR(
  80. ERROR_LEVEL_EXPECTED,
  81. "SrvAllocateConnection: Unable to allocate %d bytes from"
  82. "paged pool",
  83. sizeof( PAGED_CONNECTION ),
  84. NULL
  85. );
  86. goto error_exit;
  87. }
  88. IF_DEBUG(HEAP) {
  89. KdPrint(( "SrvAllocateConnection: Allocated connection at %p\n",
  90. connection ));
  91. }
  92. RtlZeroMemory( pagedConnection, sizeof(PAGED_CONNECTION) );
  93. SET_BLOCK_TYPE_STATE_SIZE( connection, BlockTypeConnection, BlockStateInitializing, sizeof( CONNECTION ) );
  94. connection->PagedConnection = pagedConnection;
  95. pagedConnection->PagedHeader.NonPagedBlock = connection;
  96. pagedConnection->PagedHeader.Type = BlockTypePagedConnection;
  97. connection->BlockHeader.ReferenceCount = 2; // allow for Active status
  98. // and caller's pointer
  99. InitializeListHead( &pagedConnection->TransactionList );
  100. connection->SmbDialect = SmbDialectIllegal;
  101. connection->CachedFid = (ULONG)-1;
  102. //
  103. // Allocate session table.
  104. //
  105. SrvAllocateTable(
  106. &pagedConnection->SessionTable,
  107. SrvInitialSessionTableSize,
  108. FALSE
  109. );
  110. if ( pagedConnection->SessionTable.Table == NULL ) {
  111. goto error_exit;
  112. }
  113. //
  114. // Allocate tree connect table.
  115. //
  116. SrvAllocateTable(
  117. &pagedConnection->TreeConnectTable,
  118. SrvInitialTreeTableSize,
  119. FALSE
  120. );
  121. if ( pagedConnection->TreeConnectTable.Table == NULL ) {
  122. goto error_exit;
  123. }
  124. //
  125. // Allocate file table.
  126. //
  127. SrvAllocateTable(
  128. &connection->FileTable,
  129. SrvInitialFileTableSize,
  130. TRUE
  131. );
  132. if ( connection->FileTable.Table == NULL ) {
  133. goto error_exit;
  134. }
  135. //
  136. // Allocate search table.
  137. //
  138. SrvAllocateTable(
  139. &pagedConnection->SearchTable,
  140. SrvInitialSearchTableSize,
  141. FALSE
  142. );
  143. if ( pagedConnection->SearchTable.Table == NULL ) {
  144. goto error_exit;
  145. }
  146. //
  147. // Initialize core search list heads
  148. //
  149. InitializeListHead( &pagedConnection->CoreSearchList );
  150. //
  151. // Initialize the locks that protect the connection and its data.
  152. //
  153. INITIALIZE_SPIN_LOCK( &connection->SpinLock );
  154. INITIALIZE_SPIN_LOCK( &connection->Interlock );
  155. INITIALIZE_LOCK( &connection->Lock, CONNECTION_LOCK_LEVEL, "ConnectionLock" );
  156. INITIALIZE_LOCK( &connection->LicenseLock, LICENSE_LOCK_LEVEL, "LicenseLock" );
  157. //
  158. // Initialize the client machine name string.
  159. //
  160. pagedConnection->ClientMachineNameString.Buffer =
  161. pagedConnection->LeadingSlashes;
  162. pagedConnection->ClientMachineNameString.Length = 0;
  163. pagedConnection->ClientMachineNameString.MaximumLength =
  164. (USHORT)((2 + COMPUTER_NAME_LENGTH + 1) * sizeof(WCHAR));
  165. pagedConnection->LeadingSlashes[0] = '\\';
  166. pagedConnection->LeadingSlashes[1] = '\\';
  167. #ifdef INCLUDE_SMB_PERSISTENT
  168. pagedConnection->PersistentId = 0;
  169. pagedConnection->PersistentFileOffset = 0;
  170. pagedConnection->PersistentState = PersistentStateFreed;
  171. #endif
  172. //
  173. // Initialize the oem client machine name string
  174. //
  175. connection->OemClientMachineNameString.Buffer =
  176. connection->OemClientMachineName;
  177. connection->OemClientMachineNameString.MaximumLength =
  178. (USHORT)(COMPUTER_NAME_LENGTH + 1);
  179. //
  180. // Initialize count of sessions.
  181. //
  182. // *** Already done by RtlZeroMemory.
  183. //pagedConnection->CurrentNumberOfSessions = 0;
  184. //
  185. // Initialize the in-progress work item list, the outstanding
  186. // oplock breaks list, and the cached-after-close lists.
  187. //
  188. InitializeListHead( &connection->InProgressWorkItemList );
  189. InitializeListHead( &connection->OplockWorkList );
  190. InitializeListHead( &connection->CachedOpenList );
  191. InitializeListHead( &connection->CachedDirectoryList );
  192. // Initialize the CachedTransactionList
  193. ExInitializeSListHead( &connection->CachedTransactionList );
  194. SET_INVALID_CONTEXT_HANDLE(connection->NegotiateHandle);
  195. //
  196. // Indicate that security signatures are not active
  197. //
  198. connection->SmbSecuritySignatureActive = FALSE;
  199. //
  200. // Indicate that no IPX saved response buffer has been allocated.
  201. //
  202. connection->LastResponse = connection->BuiltinSavedResponse;
  203. //
  204. // Initialize the search hash table list.
  205. //
  206. for ( i = 0; i < SEARCH_HASH_TABLE_SIZE ; i++ ) {
  207. InitializeListHead( &pagedConnection->SearchHashTable[i].ListHead );
  208. }
  209. INITIALIZE_REFERENCE_HISTORY( connection );
  210. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.ConnectionInfo.Allocations );
  211. return;
  212. error_exit:
  213. if ( pagedConnection != NULL ) {
  214. if ( pagedConnection->SessionTable.Table != NULL ) {
  215. SrvFreeTable( &pagedConnection->SessionTable );
  216. }
  217. if ( pagedConnection->TreeConnectTable.Table != NULL ) {
  218. SrvFreeTable( &pagedConnection->TreeConnectTable );
  219. }
  220. if ( pagedConnection->SearchTable.Table != NULL ) {
  221. SrvFreeTable( &pagedConnection->SearchTable );
  222. }
  223. FREE_HEAP( pagedConnection );
  224. }
  225. if ( connection != NULL ) {
  226. if ( connection->FileTable.Table != NULL ) {
  227. SrvFreeTable( &connection->FileTable );
  228. }
  229. DEALLOCATE_NONPAGED_POOL( connection );
  230. *Connection = NULL;
  231. }
  232. return;
  233. } // SrvAllocateConnection
  234. VOID
  235. SrvCloseConnection (
  236. IN PCONNECTION Connection,
  237. IN BOOLEAN RemoteDisconnect
  238. )
  239. /*++
  240. Routine Description:
  241. This function closes a connection (virtual circuit).
  242. *** This routine must NOT be entered with the connection lock held!
  243. It may be entered with the endpoint lock held.
  244. Arguments:
  245. Connection - Supplies a pointer to a Connection Block
  246. RemoteDisconnect - Indicates whether this call is being made in
  247. response to a notification by the transport provider.
  248. Return Value:
  249. None.
  250. --*/
  251. {
  252. PTABLE_HEADER tableHeader;
  253. PLIST_ENTRY listEntry;
  254. USHORT i;
  255. KIRQL oldIrql;
  256. PRFCB rfcb;
  257. ASSERT( !ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(Connection->Lock)) );
  258. ACQUIRE_LOCK( &Connection->Lock );
  259. //
  260. // If the connection hasn't already been closed, do so now.
  261. //
  262. if ( GET_BLOCK_STATE(Connection) == BlockStateActive ) {
  263. #if SRVDBG29
  264. {
  265. ULONG conn = (ULONG)Connection;
  266. if (RemoteDisconnect) conn |= 1;
  267. if (Connection->DisconnectPending) conn |= 2;
  268. UpdateConnectionHistory( "CLOS", Connection->Endpoint, Connection );
  269. }
  270. #endif
  271. IF_DEBUG(TDI) KdPrint(( "Closing connection (%s) at %p for %z\n",
  272. DisconnectReasonText[(USHORT)Connection->DisconnectReason], Connection, (PCSTRING)&Connection->OemClientMachineNameString ));
  273. IF_DEBUG( ERRORS ) {
  274. if( RemoteDisconnect == FALSE ) {
  275. KdPrint(( "SrvCloseConnection: forcibly closing connection %p (%s)\n", Connection, DisconnectReasonText[(USHORT)Connection->DisconnectReason] ));
  276. }
  277. }
  278. SET_BLOCK_STATE( Connection, BlockStateClosing );
  279. RELEASE_LOCK( &Connection->Lock );
  280. //
  281. // If the connection is on the need-resource queue (waiting for
  282. // a work item) or the disconnect queue (a Disconnect having
  283. // been indicated by the transport), remove it now, and
  284. // dereference it. (Note that the connection can't go away yet,
  285. // because the initial reference is still there.)
  286. //
  287. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  288. //
  289. // Invalidate the cached connection
  290. //
  291. if ( Connection->OnNeedResourceQueue ) {
  292. SrvRemoveEntryList(
  293. &SrvNeedResourceQueue,
  294. &Connection->ListEntry
  295. );
  296. Connection->OnNeedResourceQueue = FALSE;
  297. DEBUG Connection->ReceivePending = FALSE;
  298. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  299. SrvDereferenceConnection( Connection );
  300. } else if ( Connection->DisconnectPending ) {
  301. SrvRemoveEntryList(
  302. &SrvDisconnectQueue,
  303. &Connection->ListEntry
  304. );
  305. DEBUG Connection->DisconnectPending = FALSE;
  306. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  307. SrvDereferenceConnection( Connection );
  308. //
  309. // If there's a disconnect pending, then don't try to shut
  310. // down the connection later.
  311. //
  312. RemoteDisconnect = TRUE;
  313. } else {
  314. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  315. }
  316. //
  317. // If this is not a remote disconnect, issue a TdiDisconnect
  318. // request now.
  319. //
  320. // *** This is currently done as a synchronous request. It may
  321. // be better to do this asynchronously.
  322. //
  323. if ( !RemoteDisconnect && !Connection->Endpoint->IsConnectionless ) {
  324. SrvDoDisconnect( Connection );
  325. }
  326. //
  327. // Close all active sessions. (This also causes all open files
  328. // and pending transactions to be closed.)
  329. //
  330. SrvCloseSessionsOnConnection( Connection, NULL );
  331. //
  332. // Close all active tree connects.
  333. //
  334. // *** Reference the tree connect for the same reasons as we
  335. // referenced the session; see above.
  336. tableHeader = &Connection->PagedConnection->TreeConnectTable;
  337. ACQUIRE_LOCK( &Connection->Lock );
  338. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  339. PTREE_CONNECT treeConnect =
  340. (PTREE_CONNECT)tableHeader->Table[i].Owner;
  341. if ( treeConnect != NULL &&
  342. GET_BLOCK_STATE( treeConnect ) == BlockStateActive ) {
  343. SrvReferenceTreeConnect( treeConnect );
  344. RELEASE_LOCK( &Connection->Lock );
  345. SrvCloseTreeConnect( treeConnect );
  346. SrvDereferenceTreeConnect( treeConnect );
  347. ACQUIRE_LOCK( &Connection->Lock );
  348. }
  349. }
  350. //
  351. // If there is state associated with a extended security negotiate,
  352. // free it up.
  353. //
  354. if (IS_VALID_CONTEXT_HANDLE(Connection->NegotiateHandle)) {
  355. DeleteSecurityContext( &Connection->NegotiateHandle );
  356. }
  357. SET_INVALID_CONTEXT_HANDLE( Connection->NegotiateHandle );
  358. RELEASE_LOCK( &Connection->Lock );
  359. //
  360. // Cancel all outstanding oplock break requests.
  361. //
  362. while ( (listEntry = ExInterlockedRemoveHeadList(
  363. &Connection->OplockWorkList,
  364. Connection->EndpointSpinLock
  365. )) != NULL ) {
  366. //
  367. // Remove this work item from the connection queue and
  368. // return it to the free queue.
  369. //
  370. rfcb = CONTAINING_RECORD( listEntry, RFCB, ListEntry );
  371. #if DBG
  372. rfcb->ListEntry.Flink = rfcb->ListEntry.Blink = NULL;
  373. #endif
  374. SrvDereferenceRfcb( rfcb );
  375. }
  376. //
  377. // Close RFCBs that are cached after having been closed by the
  378. // client.
  379. //
  380. SrvCloseCachedRfcbsOnConnection( Connection );
  381. //
  382. // Dereference the connection (to indicate that it's no longer
  383. // open). This may cause the connection block to be deleted.
  384. //
  385. SrvDereferenceConnection( Connection );
  386. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.ConnectionInfo.Closes );
  387. } else {
  388. RELEASE_LOCK( &Connection->Lock );
  389. }
  390. return;
  391. } // SrvCloseConnection
  392. VOID
  393. SrvCloseConnectionsFromClient (
  394. IN PCONNECTION Connection,
  395. IN BOOLEAN OnlyIfNoSessions
  396. )
  397. /*++
  398. Routine Description:
  399. This routine closes all connections from a given remote machine name
  400. except the connection passed in. This is used in the Session Setup
  401. SMB when the client indicates that he believes that he has exactly
  402. one connection to this server; if there are others, we know that
  403. they are not valid.
  404. Arguments:
  405. Connection - Address of connection to keep around. This is used
  406. for the machine name.
  407. OnlyIfNoSessions - Kill off the duplicate connections only if they do
  408. not have any established sessions.
  409. Return Value:
  410. None.
  411. --*/
  412. {
  413. USHORT index;
  414. PENDPOINT endpoint;
  415. PLIST_ENTRY listEntry;
  416. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  417. PPAGED_CONNECTION testPagedConnection;
  418. PCONNECTION testConnection;
  419. BOOLEAN Connectionless = Connection->Endpoint->IsConnectionless == 1;
  420. BOOLEAN IsIPAddress = (Connection->ClientIPAddress != 0);
  421. PAGED_CODE( );
  422. //
  423. // We need to look at the name of every client for which the server
  424. // has a connection. Connection lists are stored off endpoints, so
  425. // walk the global endpoint list and the list of connections on each
  426. // endpoint.
  427. //
  428. IF_DEBUG(TDI) {
  429. KdPrint(( "SrvCloseConnectionsFromClient entered for connection "
  430. "%p, OemName %z, looking for %wZ\n", Connection,
  431. (PCSTRING)&Connection->OemClientMachineNameString,
  432. &pagedConnection->ClientMachineNameString));
  433. }
  434. ACQUIRE_LOCK( &SrvEndpointLock );
  435. listEntry = SrvEndpointList.ListHead.Flink;
  436. while ( listEntry != &SrvEndpointList.ListHead ) {
  437. endpoint = CONTAINING_RECORD(
  438. listEntry,
  439. ENDPOINT,
  440. GlobalEndpointListEntry
  441. );
  442. //
  443. // If this endpoint is closing, or if the types don't match,
  444. // skip to the next one.
  445. // Otherwise, reference the endpoint so that it can't go away.
  446. //
  447. if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ||
  448. endpoint->IsConnectionless != Connectionless ) {
  449. listEntry = listEntry->Flink;
  450. continue;
  451. }
  452. //
  453. // If this endpoint doesn't have the same netbios name as the
  454. // endpoint of the passed-in connection then skip it. This is
  455. // to allow servers to have more than one name on the network.
  456. //
  457. if( Connection->Endpoint->TransportAddress.Length !=
  458. endpoint->TransportAddress.Length ||
  459. !RtlEqualMemory( Connection->Endpoint->TransportAddress.Buffer,
  460. endpoint->TransportAddress.Buffer,
  461. endpoint->TransportAddress.Length ) ) {
  462. //
  463. // This connection is for an endpoint having a different network
  464. // name than does this endpoint. Skip this endpoint.
  465. //
  466. listEntry = listEntry->Flink;
  467. continue;
  468. }
  469. #if 0
  470. //
  471. // If this endpoint doesn't have the same transport name as the one
  472. // on which the client is connecting, then skip it. This is for
  473. // multihomed servers.
  474. //
  475. if( Connection->Endpoint->TransportName.Length !=
  476. endpoint->TransportName.Length ||
  477. !RtlEqualMemory( Connection->Endpoint->TransportName.Buffer,
  478. endpoint->TransportName.Buffer,
  479. endpoint->TransportName.Length ) ) {
  480. //
  481. // This connection is for an endpoint coming in over a different
  482. // stack instance.
  483. //
  484. listEntry = listEntry->Flink;
  485. continue;
  486. }
  487. #endif
  488. SrvReferenceEndpoint( endpoint );
  489. //
  490. // Walk the endpoint's connection table.
  491. //
  492. index = (USHORT)-1;
  493. while ( TRUE ) {
  494. //
  495. // Get the next active connection in the table. If no more
  496. // are available, WalkConnectionTable returns NULL.
  497. // Otherwise, it returns a referenced pointer to a
  498. // connection.
  499. //
  500. testConnection = WalkConnectionTable( endpoint, &index );
  501. if ( testConnection == NULL ) {
  502. break;
  503. }
  504. if( testConnection == Connection ) {
  505. //
  506. // Skip ourselves!
  507. //
  508. SrvDereferenceConnection( testConnection );
  509. continue;
  510. }
  511. testPagedConnection = testConnection->PagedConnection;
  512. if( OnlyIfNoSessions == TRUE &&
  513. testPagedConnection->CurrentNumberOfSessions != 0 ) {
  514. //
  515. // This connection has sessions. Skip it.
  516. //
  517. SrvDereferenceConnection( testConnection );
  518. continue;
  519. }
  520. if( Connectionless ) {
  521. //
  522. // Connectionless clients match on IPX address...
  523. //
  524. if( !RtlEqualMemory( &Connection->IpxAddress,
  525. &testConnection->IpxAddress,
  526. sizeof(Connection->IpxAddress) ) ) {
  527. SrvDereferenceConnection( testConnection );
  528. continue;
  529. }
  530. } else {
  531. //
  532. // If the IP address matches, then nuke this client
  533. //
  534. if( IsIPAddress &&
  535. Connection->ClientIPAddress == testConnection->ClientIPAddress ) {
  536. goto nuke_it;
  537. }
  538. //
  539. // If the computer name matches, then nuke this client
  540. //
  541. if ( RtlCompareUnicodeString(
  542. &testPagedConnection->ClientMachineNameString,
  543. &pagedConnection->ClientMachineNameString,
  544. TRUE
  545. ) == 0 ) {
  546. goto nuke_it;
  547. }
  548. //
  549. // Neither the IP address nor the name match -- skip this client
  550. //
  551. SrvDereferenceConnection( testConnection );
  552. continue;
  553. }
  554. nuke_it:
  555. //
  556. // We found a connection that we need to kill. We
  557. // have to release the lock in order to close it.
  558. //
  559. RELEASE_LOCK( &SrvEndpointLock );
  560. IF_DEBUG(TDI) {
  561. KdPrint(( "SrvCloseConnectionsFromClient closing "
  562. "connection %p, MachineNameString %Z\n",
  563. testConnection,
  564. &testPagedConnection->ClientMachineNameString ));
  565. }
  566. #if SRVDBG29
  567. UpdateConnectionHistory( "CFC1", testConnection->Endpoint, testConnection );
  568. UpdateConnectionHistory( "CFC2", testConnection->Endpoint, Connection );
  569. #endif
  570. testConnection->DisconnectReason = DisconnectNewSessionSetupOnConnection;
  571. SrvCloseConnection( testConnection, FALSE );
  572. ACQUIRE_LOCK( &SrvEndpointLock );
  573. //
  574. // Dereference the connection to account for the reference
  575. // from WalkConnectionTable.
  576. //
  577. SrvDereferenceConnection( testConnection );
  578. } // walk connection table
  579. //
  580. // Capture a pointer to the next endpoint in the list (that one
  581. // can't go away because we hold the endpoint list), then
  582. // dereference the current endpoint.
  583. //
  584. listEntry = listEntry->Flink;
  585. SrvDereferenceEndpoint( endpoint );
  586. } // walk endpoint list
  587. RELEASE_LOCK( &SrvEndpointLock );
  588. } // SrvCloseConnectionsFromClient
  589. VOID
  590. SrvCloseFreeConnection (
  591. IN PCONNECTION Connection
  592. )
  593. /*++
  594. Routine Description:
  595. This function closes a free connection. This is a connection that
  596. is not active -- has already been closed via SrvCloseConnection --
  597. and is no longer needed.
  598. *** WARNING! This routine frees the storage occupied by Connection!
  599. Arguments:
  600. Connection - Supplies a pointer to a Connection Block
  601. Return Value:
  602. None.
  603. --*/
  604. {
  605. PENDPOINT endpoint;
  606. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  607. KIRQL oldIrql;
  608. ASSERT( Connection->BlockHeader.ReferenceCount == 0 );
  609. endpoint = Connection->Endpoint;
  610. ACQUIRE_LOCK( &SrvEndpointLock );
  611. //
  612. // Remove the connection from the endpoint's connection table.
  613. //
  614. if ( Connection->Sid != 0 ) {
  615. ACQUIRE_SPIN_LOCK( Connection->EndpointSpinLock, &oldIrql );
  616. SrvRemoveEntryTable(
  617. &endpoint->ConnectionTable,
  618. Connection->SidIndex
  619. );
  620. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, oldIrql );
  621. Connection->Sid = 0;
  622. }
  623. //
  624. // Decrement the count of connections for the endpoint.
  625. //
  626. ExInterlockedAddUlong(
  627. &endpoint->TotalConnectionCount,
  628. (ULONG)-1,
  629. &GLOBAL_SPIN_LOCK(Fsd)
  630. );
  631. RELEASE_LOCK( &SrvEndpointLock );
  632. //
  633. // Close the connection file object. Remove the additional
  634. // reference.
  635. //
  636. if ( !endpoint->IsConnectionless ) {
  637. SRVDBG_RELEASE_HANDLE( pagedConnection->ConnectionHandle, "CON", 1, Connection );
  638. SrvNtClose( pagedConnection->ConnectionHandle, FALSE );
  639. ObDereferenceObject( Connection->FileObject );
  640. }
  641. //
  642. // Dereference the endpoint.
  643. //
  644. SrvDereferenceEndpoint( endpoint );
  645. //
  646. // Free the storage occupied by the connection.
  647. //
  648. SrvFreeConnection( Connection );
  649. return;
  650. } // SrvCloseFreeConnection
  651. VOID
  652. SrvDereferenceConnection (
  653. IN PCONNECTION Connection
  654. )
  655. /*++
  656. Routine Description:
  657. This function decrements the reference count on a connection. If the
  658. reference count goes to zero, the connection block is deleted.
  659. The connection lock must not be held when this routine is called,
  660. because the global endpoint lock, which has a lower level, must be
  661. acquired.
  662. Arguments:
  663. Connection - Address of connection
  664. Return Value:
  665. None.
  666. --*/
  667. {
  668. ULONG oldCount;
  669. PENDPOINT endpoint;
  670. KIRQL oldIrql;
  671. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  672. ASSERT( GET_BLOCK_TYPE( Connection ) == BlockTypeConnection );
  673. ASSERT( (LONG)Connection->BlockHeader.ReferenceCount > 0 );
  674. UPDATE_REFERENCE_HISTORY( Connection, TRUE );
  675. //
  676. // Perform an interlocked decrement of the connection block's
  677. // reference count.
  678. //
  679. // *** Note that we don't hold a lock between the time we decrement
  680. // the reference count and the time we delete the connection
  681. // block. Normally this would imply that the FSD could
  682. // reference the block in between. However, the transport
  683. // provider guarantees that it won't deliver any more events
  684. // after a remote Disconnect event or after a local
  685. // TdiDisconnect request, and one of those two things has to
  686. // happen before the reference count can go to 0 (see
  687. // SrvCloseConnection).
  688. //
  689. oldCount = ExInterlockedAddUlong(
  690. &Connection->BlockHeader.ReferenceCount,
  691. (ULONG)-1,
  692. Connection->EndpointSpinLock
  693. );
  694. IF_DEBUG(REFCNT) {
  695. KdPrint(( "Dereferencing connection %p; old refcnt %lx\n",
  696. Connection, oldCount ));
  697. }
  698. if ( oldCount == 1 ) {
  699. //
  700. // The new reference count is 0, meaning that it's time to
  701. // delete this block.
  702. //
  703. ASSERT( GET_BLOCK_STATE(Connection) != BlockStateActive );
  704. #if SRVDBG29
  705. if ( GET_BLOCK_STATE(Connection) != BlockStateClosing ) {
  706. KdPrint(( "SRV: Connection is not CLOSING with refcnt 0!\n" ));
  707. DbgBreakPoint( );
  708. }
  709. #endif
  710. //
  711. // Free the space allocated for client Domain, OS Name, and
  712. // LAN type.
  713. //
  714. if ( Connection->ClientOSType.Buffer != NULL ) {
  715. DEALLOCATE_NONPAGED_POOL( Connection->ClientOSType.Buffer );
  716. Connection->ClientOSType.Buffer = NULL;
  717. }
  718. //
  719. // Keep the WORK_QUEUE statistic correct
  720. //
  721. if( Connection->CurrentWorkQueue )
  722. InterlockedDecrement( &Connection->CurrentWorkQueue->CurrentClients );
  723. // (Always TRUE) ASSERT( Connection->CurrentWorkQueue->CurrentClients >= 0 );
  724. endpoint = Connection->Endpoint;
  725. ACQUIRE_LOCK( &SrvEndpointLock );
  726. //
  727. // If the connection hasn't been marked as not reusable (e.g.,
  728. // because a disconnect failed), and the endpoint isn't closing,
  729. // and it isn't already "full" of free connections, put this
  730. // connection on the endpoint's free connection list.
  731. // Otherwise, close the connection file object and free the
  732. // connection block.
  733. //
  734. if ( !Connection->NotReusable &&
  735. (GET_BLOCK_STATE(endpoint) == BlockStateActive) &&
  736. (endpoint->FreeConnectionCount < SrvFreeConnectionMaximum) ) {
  737. //
  738. // Reinitialize the connection state.
  739. //
  740. // !!! Should probably reset the connection's table sizes,
  741. // if they've grown.
  742. //
  743. SET_BLOCK_STATE( Connection, BlockStateInitializing );
  744. pagedConnection->LinkInfoValidTime.QuadPart = 0;
  745. pagedConnection->Throughput.QuadPart = 0;
  746. pagedConnection->Delay.QuadPart = 0;
  747. pagedConnection->CurrentNumberOfSessions = 0;
  748. pagedConnection->ClientMachineNameString.Length = 0;
  749. Connection->ClientCapabilities = 0;
  750. Connection->SmbDialect = SmbDialectIllegal;
  751. Connection->DisconnectPending = FALSE;
  752. Connection->ReceivePending = FALSE;
  753. Connection->OplocksAlwaysDisabled = FALSE;
  754. Connection->CachedFid = (ULONG)-1;
  755. Connection->InProgressWorkContextCount = 0;
  756. Connection->IsConnectionSuspect = FALSE;
  757. Connection->DisconnectReason = DisconnectReasons;
  758. Connection->OperationsPendingOnTransport = 0;
  759. //
  760. // Put the connection on the free list.
  761. //
  762. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  763. #if SRVDBG29
  764. UpdateConnectionHistory( "KEEP", endpoint, Connection );
  765. #endif
  766. SrvInsertTailList(
  767. &endpoint->FreeConnectionList,
  768. &Connection->EndpointFreeListEntry
  769. );
  770. endpoint->FreeConnectionCount++;
  771. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  772. RELEASE_LOCK( &SrvEndpointLock );
  773. } else {
  774. RELEASE_LOCK( &SrvEndpointLock );
  775. SrvCloseFreeConnection( Connection );
  776. }
  777. }
  778. return;
  779. } // SrvDereferenceConnection
  780. VOID
  781. SrvFreeConnection (
  782. IN PCONNECTION Connection
  783. )
  784. /*++
  785. Routine Description:
  786. This function returns a Connection Block to the system nonpaged
  787. pool.
  788. Arguments:
  789. Connection - Address of connection
  790. Return Value:
  791. None.
  792. --*/
  793. {
  794. PSINGLE_LIST_ENTRY listEntry;
  795. PNONPAGED_HEADER header;
  796. PTRANSACTION transaction;
  797. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  798. #if 0
  799. //
  800. // ENSURE WE ARE NOT STILL IN THE CONNECTION TABLE FOR THE ENDPOINT!
  801. //
  802. if( Connection->Endpoint ) {
  803. PTABLE_HEADER tableHeader = &Connection->Endpoint->ConnectionTable;
  804. USHORT i;
  805. KIRQL oldIrql;
  806. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  807. for ( i = 1; i < ENDPOINT_LOCK_COUNT ; i++ ) {
  808. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  809. }
  810. for( i = 0; i < tableHeader->TableSize; i++ ) {
  811. if( (PCONNECTION)tableHeader->Table[i].Owner == Connection ) {
  812. DbgPrint( "SRV: SrvFreeConnection(%p), but connection still in endpoint %p ConnectionTable\n",
  813. Connection, Connection->Endpoint );
  814. DbgPrint( " Entry number %d, addr %p\n", i, &tableHeader->Table[i] );
  815. DbgPrint( " Connection->Sid %X, IPXSID %d\n", Connection->Sid, IPXSID_INDEX(Connection->Sid));
  816. DbgBreakPoint();
  817. break;
  818. }
  819. }
  820. for ( i = ENDPOINT_LOCK_COUNT-1 ; i > 0 ; i-- ) {
  821. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  822. }
  823. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  824. }
  825. #endif
  826. //
  827. // Free cached transactions.
  828. //
  829. listEntry = ExInterlockedPopEntrySList( &Connection->CachedTransactionList,
  830. &Connection->SpinLock );
  831. while ( listEntry != NULL ) {
  832. header = CONTAINING_RECORD( listEntry, NONPAGED_HEADER, ListEntry );
  833. transaction = header->PagedBlock;
  834. DEALLOCATE_NONPAGED_POOL( header );
  835. FREE_HEAP( transaction );
  836. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TransactionInfo.Frees );
  837. listEntry = ExInterlockedPopEntrySList(
  838. &Connection->CachedTransactionList,
  839. &Connection->SpinLock );
  840. }
  841. //
  842. // Free the search, session, tree, and file tables.
  843. //
  844. SrvFreeTable( &pagedConnection->SearchTable );
  845. SrvFreeTable( &Connection->FileTable );
  846. SrvFreeTable( &pagedConnection->TreeConnectTable );
  847. SrvFreeTable( &pagedConnection->SessionTable );
  848. //
  849. // Free the IPX saved response buffer, if there is one.
  850. //
  851. if ( Connection->DirectHostIpx == TRUE &&
  852. Connection->LastResponse != Connection->BuiltinSavedResponse ) {
  853. DEALLOCATE_NONPAGED_POOL( Connection->LastResponse );
  854. }
  855. //
  856. // Delete the lock on the connection.
  857. //
  858. DELETE_LOCK( &Connection->Lock );
  859. //
  860. // Delete the license server lock
  861. //
  862. DELETE_LOCK( &Connection->LicenseLock );
  863. //
  864. // Free the connection block.
  865. //
  866. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Connection, BlockTypeGarbage, BlockStateDead, -1 );
  867. DEBUG Connection->BlockHeader.ReferenceCount = (ULONG)-1;
  868. TERMINATE_REFERENCE_HISTORY( Connection );
  869. FREE_HEAP( pagedConnection );
  870. DEALLOCATE_NONPAGED_POOL( Connection );
  871. IF_DEBUG(HEAP) {
  872. KdPrint(( "SrvFreeConnection: Freed connection block at %p\n",
  873. Connection ));
  874. }
  875. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.ConnectionInfo.Frees );
  876. return;
  877. } // SrvFreeConnection
  878. #if DBG
  879. NTSTATUS
  880. SrvQueryConnections (
  881. OUT PVOID Buffer,
  882. IN ULONG BufferLength,
  883. OUT PULONG BytesWritten
  884. )
  885. {
  886. USHORT index;
  887. PLIST_ENTRY listEntry;
  888. PLIST_ENTRY connectionListEntry;
  889. PBLOCK_INFORMATION blockInfo = Buffer;
  890. PENDPOINT endpoint;
  891. PCONNECTION connection;
  892. KIRQL oldIrql;
  893. *BytesWritten = 0;
  894. //
  895. // We need to look at the name of every client for which the server
  896. // has a connection. Connection lists are stored off endpoints, so
  897. // walk the global endpoint list and the list of connections on each
  898. // endpoint.
  899. //
  900. ACQUIRE_LOCK( &SrvEndpointLock );
  901. listEntry = SrvEndpointList.ListHead.Flink;
  902. while ( listEntry != &SrvEndpointList.ListHead ) {
  903. endpoint = CONTAINING_RECORD(
  904. listEntry,
  905. ENDPOINT,
  906. GlobalEndpointListEntry
  907. );
  908. //
  909. // If this endpoint is closing, skip to the next one.
  910. // Otherwise, reference the endpoint so that it can't go away.
  911. //
  912. if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ) {
  913. listEntry = listEntry->Flink;
  914. continue;
  915. }
  916. SrvReferenceEndpoint( endpoint );
  917. //
  918. // Put information about the endpoint into the output buffer.
  919. //
  920. if ( (PCHAR)(blockInfo + 1) <= (PCHAR)Buffer + BufferLength ) {
  921. blockInfo->Block = endpoint;
  922. blockInfo->BlockType = (ULONG)BlockTypeEndpoint;
  923. blockInfo->BlockState = (ULONG)endpoint->BlockHeader.State;
  924. blockInfo->ReferenceCount = endpoint->BlockHeader.ReferenceCount;
  925. blockInfo++;
  926. } else {
  927. SrvDereferenceEndpoint( endpoint );
  928. RELEASE_LOCK( &SrvEndpointLock );
  929. return STATUS_BUFFER_OVERFLOW;
  930. }
  931. //
  932. // Walk the connection table, writing information about each
  933. // connection to the output buffer.
  934. //
  935. index = (USHORT)-1;
  936. while ( TRUE ) {
  937. //
  938. // Get the next active connection in the table. If no more
  939. // are available, WalkConnectionTable returns NULL.
  940. // Otherwise, it returns a referenced pointer to a
  941. // connection.
  942. //
  943. connection = WalkConnectionTable( endpoint, &index );
  944. if ( connection == NULL ) {
  945. break;
  946. }
  947. if ( (PCHAR)(blockInfo + 1) <= (PCHAR)Buffer + BufferLength ) {
  948. blockInfo->Block = connection;
  949. blockInfo->BlockType = (ULONG)BlockTypeConnection;
  950. blockInfo->BlockState = (ULONG)connection->BlockHeader.State;
  951. blockInfo->ReferenceCount =
  952. connection->BlockHeader.ReferenceCount;
  953. blockInfo++;
  954. SrvDereferenceConnection( connection );
  955. } else {
  956. SrvDereferenceConnection( connection );
  957. SrvDereferenceEndpoint( endpoint );
  958. RELEASE_LOCK( &SrvEndpointLock );
  959. return STATUS_BUFFER_OVERFLOW;
  960. }
  961. } // walk connection list
  962. //
  963. // Walk the free connection list, writing information about each
  964. // connection to the output buffer.
  965. //
  966. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  967. for ( connectionListEntry = endpoint->FreeConnectionList.Flink;
  968. connectionListEntry != &endpoint->FreeConnectionList;
  969. connectionListEntry = connectionListEntry->Flink ) {
  970. connection = CONTAINING_RECORD(
  971. connectionListEntry,
  972. CONNECTION,
  973. EndpointFreeListEntry
  974. );
  975. if ( (PCHAR)(blockInfo + 1) <= (PCHAR)Buffer + BufferLength ) {
  976. blockInfo->Block = connection;
  977. blockInfo->BlockType = (ULONG)BlockTypeConnection;
  978. blockInfo->BlockState = (ULONG)connection->BlockHeader.State;
  979. blockInfo->ReferenceCount =
  980. connection->BlockHeader.ReferenceCount;
  981. blockInfo++;
  982. } else {
  983. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  984. RELEASE_LOCK( &SrvEndpointLock );
  985. return STATUS_BUFFER_OVERFLOW;
  986. }
  987. } // walk free connection list
  988. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  989. //
  990. // Capture a pointer to the next endpoint in the list (that one
  991. // can't go away because we hold the endpoint list), then
  992. // dereference the current endpoint.
  993. //
  994. listEntry = listEntry->Flink;
  995. SrvDereferenceEndpoint( endpoint );
  996. } // walk endpoint list
  997. RELEASE_LOCK( &SrvEndpointLock );
  998. *BytesWritten = (ULONG)((PCHAR)blockInfo - (PCHAR)Buffer);
  999. return STATUS_SUCCESS;
  1000. } // SrvQueryConnections
  1001. #endif // if DBG