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.

859 lines
23 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blkendp.c
  5. Abstract:
  6. This module implements routines for managing endpoint blocks.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 4-Oct-1989
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "blkendp.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKENDP
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvAllocateEndpoint )
  17. #pragma alloc_text( PAGE, SrvCheckAndReferenceEndpoint )
  18. #pragma alloc_text( PAGE, SrvCloseEndpoint )
  19. #pragma alloc_text( PAGE, SrvDereferenceEndpoint )
  20. #pragma alloc_text( PAGE, SrvFreeEndpoint )
  21. #pragma alloc_text( PAGE, SrvReferenceEndpoint )
  22. #pragma alloc_text( PAGE, SrvFindNamedEndpoint )
  23. #endif
  24. #if 0
  25. NOT PAGEABLE -- EmptyFreeConnectionList
  26. NOT PAGEABLE -- WalkConnectionTable
  27. #endif
  28. VOID
  29. SrvAllocateEndpoint (
  30. OUT PENDPOINT *Endpoint,
  31. IN PUNICODE_STRING NetworkName,
  32. IN PUNICODE_STRING TransportName,
  33. IN PANSI_STRING TransportAddress,
  34. IN PUNICODE_STRING DomainName
  35. )
  36. /*++
  37. Routine Description:
  38. This function allocates an Endpoint Block from the system nonpaged
  39. pool.
  40. Arguments:
  41. Endpoint - Returns a pointer to the endpoint block, or NULL if no
  42. pool was available.
  43. NetworkName - Supplies a pointer to the network name (e.g., NET1).
  44. TransportName - The fully qualified name of the transport device.
  45. For example, "\Device\Nbf".
  46. TransportAddress - The fully qualified address (or name ) of the
  47. server's endpoint. This name is used exactly as specified. For
  48. NETBIOS-compatible networks, the caller must upcase and
  49. blank-fill the name. E.g., "\Device\Nbf\NTSERVERbbbbbbbb".
  50. DomainName - the domain being serviced by this endpoint
  51. Return Value:
  52. None.
  53. --*/
  54. {
  55. CLONG length;
  56. PENDPOINT endpoint;
  57. NTSTATUS status;
  58. PAGED_CODE( );
  59. //
  60. // Attempt to allocate from nonpaged pool.
  61. //
  62. length = sizeof(ENDPOINT) +
  63. NetworkName->Length + sizeof(*NetworkName->Buffer) +
  64. TransportName->Length + sizeof(*TransportName->Buffer) +
  65. TransportAddress->Length + sizeof(*TransportAddress->Buffer) +
  66. RtlOemStringToUnicodeSize( TransportAddress ) +
  67. DNLEN * sizeof( *DomainName->Buffer ) +
  68. DNLEN + sizeof(CHAR);
  69. endpoint = ALLOCATE_NONPAGED_POOL( length, BlockTypeEndpoint );
  70. *Endpoint = endpoint;
  71. if ( endpoint == NULL ) {
  72. INTERNAL_ERROR (
  73. ERROR_LEVEL_EXPECTED,
  74. "SrvAllocateEndpoint: Unable to allocate %d bytes from nonpaged "
  75. "pool.",
  76. length,
  77. NULL
  78. );
  79. return;
  80. }
  81. IF_DEBUG(HEAP) {
  82. SrvPrint1( "SrvAllocateEndpoint: Allocated endpoint at %p\n",
  83. endpoint );
  84. }
  85. //
  86. // Initialize the endpoint block. Zero it first.
  87. //
  88. RtlZeroMemory( endpoint, length );
  89. SET_BLOCK_TYPE_STATE_SIZE( endpoint, BlockTypeEndpoint, BlockStateActive, length );
  90. endpoint->BlockHeader.ReferenceCount = 2; // allow for Active status
  91. // and caller's pointer
  92. //
  93. // Allocate connection table.
  94. //
  95. SrvAllocateTable(
  96. &endpoint->ConnectionTable,
  97. 6, // !!!
  98. TRUE
  99. );
  100. if ( endpoint->ConnectionTable.Table == NULL ) {
  101. DEALLOCATE_NONPAGED_POOL( endpoint );
  102. *Endpoint = NULL;
  103. return;
  104. }
  105. InitializeListHead( &endpoint->FreeConnectionList );
  106. #if SRVDBG29
  107. UpdateConnectionHistory( "INIT", endpoint, NULL );
  108. #endif
  109. //
  110. // Copy the network name, transport name, and server address, and domain
  111. // name into the block.
  112. //
  113. endpoint->NetworkName.Length = NetworkName->Length;
  114. endpoint->NetworkName.MaximumLength =
  115. (SHORT)(NetworkName->Length + sizeof(*NetworkName->Buffer));
  116. endpoint->NetworkName.Buffer = (PWCH)(endpoint + 1);
  117. RtlCopyMemory(
  118. endpoint->NetworkName.Buffer,
  119. NetworkName->Buffer,
  120. NetworkName->Length
  121. );
  122. endpoint->TransportName.Length = TransportName->Length;
  123. endpoint->TransportName.MaximumLength =
  124. (SHORT)(TransportName->Length + sizeof(*TransportName->Buffer));
  125. endpoint->TransportName.Buffer =
  126. (PWCH)((PCHAR)endpoint->NetworkName.Buffer +
  127. endpoint->NetworkName.MaximumLength);
  128. RtlCopyMemory(
  129. endpoint->TransportName.Buffer,
  130. TransportName->Buffer,
  131. TransportName->Length
  132. );
  133. endpoint->ServerName.MaximumLength = (USHORT)RtlOemStringToUnicodeSize( TransportAddress );
  134. endpoint->ServerName.Length = 0;
  135. endpoint->ServerName.Buffer = endpoint->TransportName.Buffer +
  136. endpoint->TransportName.MaximumLength / sizeof( WCHAR );
  137. endpoint->TransportAddress.Length = TransportAddress->Length;
  138. endpoint->TransportAddress.MaximumLength =
  139. (SHORT)(TransportAddress->Length + 1);
  140. endpoint->TransportAddress.Buffer =
  141. (PCHAR)endpoint->ServerName.Buffer +
  142. endpoint->ServerName.MaximumLength;
  143. RtlCopyMemory(
  144. endpoint->TransportAddress.Buffer,
  145. TransportAddress->Buffer,
  146. TransportAddress->Length
  147. );
  148. status = RtlOemStringToUnicodeString( &endpoint->ServerName, TransportAddress, FALSE );
  149. if (!NT_SUCCESS(status)) {
  150. DbgPrint("SRv ENDPOINT Name translation failed status %lx\n",status);
  151. KdPrint(("SRv ENDPOINT Name translation failed status %lx\n",status));
  152. }
  153. //
  154. // Trim the trailing blanks off the end of servername
  155. //
  156. while( endpoint->ServerName.Length &&
  157. endpoint->ServerName.Buffer[ (endpoint->ServerName.Length / sizeof(WCHAR))-1 ] == L' ' ) {
  158. endpoint->ServerName.Length -= sizeof( WCHAR );
  159. }
  160. endpoint->DomainName.Length = DomainName->Length;
  161. endpoint->DomainName.MaximumLength = DNLEN * sizeof( *endpoint->DomainName.Buffer );
  162. endpoint->DomainName.Buffer = (PWCH)((PCHAR)endpoint->TransportAddress.Buffer +
  163. TransportAddress->MaximumLength);
  164. RtlCopyMemory(
  165. endpoint->DomainName.Buffer,
  166. DomainName->Buffer,
  167. DomainName->Length
  168. );
  169. endpoint->OemDomainName.Length = (SHORT)RtlUnicodeStringToOemSize( DomainName );
  170. endpoint->OemDomainName.MaximumLength = DNLEN + sizeof( CHAR );
  171. endpoint->OemDomainName.Buffer = (PCHAR)endpoint->DomainName.Buffer +
  172. endpoint->DomainName.MaximumLength;
  173. status = RtlUnicodeStringToOemString(
  174. &endpoint->OemDomainName,
  175. &endpoint->DomainName,
  176. FALSE // Do not allocate the OEM string
  177. );
  178. ASSERT( NT_SUCCESS(status) );
  179. //
  180. // Initialize the network address field.
  181. //
  182. endpoint->NetworkAddress.Buffer = endpoint->NetworkAddressData;
  183. endpoint->NetworkAddress.Length = sizeof( endpoint->NetworkAddressData ) -
  184. sizeof(endpoint->NetworkAddressData[0]);
  185. endpoint->NetworkAddress.MaximumLength = sizeof( endpoint->NetworkAddressData );
  186. //
  187. // Increment the count of endpoints in the server.
  188. //
  189. ACQUIRE_LOCK( &SrvEndpointLock );
  190. SrvEndpointCount++;
  191. // If an endpoint is coming back after a NIC disconnect, reset the event
  192. if( SrvEndpointCount == 1 )
  193. {
  194. KeResetEvent( &SrvEndpointEvent );
  195. }
  196. RELEASE_LOCK( &SrvEndpointLock );
  197. INITIALIZE_REFERENCE_HISTORY( endpoint );
  198. INCREMENT_DEBUG_STAT( SrvDbgStatistics.EndpointInfo.Allocations );
  199. return;
  200. } // SrvAllocateEndpoint
  201. BOOLEAN SRVFASTCALL
  202. SrvCheckAndReferenceEndpoint (
  203. PENDPOINT Endpoint
  204. )
  205. /*++
  206. Routine Description:
  207. This function atomically verifies that an endpoint is active and
  208. increments the reference count on the endpoint if it is.
  209. Arguments:
  210. Endpoint - Address of endpoint
  211. Return Value:
  212. BOOLEAN - Returns TRUE if the endpoint is active, FALSE otherwise.
  213. --*/
  214. {
  215. PAGED_CODE( );
  216. //
  217. // Acquire the lock that guards the endpoint's state field.
  218. //
  219. ACQUIRE_LOCK( &SrvEndpointLock );
  220. //
  221. // If the endpoint is active, reference it and return TRUE.
  222. //
  223. if ( GET_BLOCK_STATE(Endpoint) == BlockStateActive ) {
  224. SrvReferenceEndpoint( Endpoint );
  225. RELEASE_LOCK( &SrvEndpointLock );
  226. return TRUE;
  227. }
  228. //
  229. // The endpoint isn't active. Return FALSE.
  230. //
  231. RELEASE_LOCK( &SrvEndpointLock );
  232. return FALSE;
  233. } // SrvCheckAndReferenceEndpoint
  234. VOID
  235. SrvCloseEndpoint (
  236. IN PENDPOINT Endpoint
  237. )
  238. /*++
  239. Routine Description:
  240. This function closes a transport endpoint.
  241. *** This function must be called with SrvEndpointLock held exactly
  242. once. The lock is released on exit.
  243. Arguments:
  244. Endpoint - Supplies a pointer to an Endpoint Block
  245. Return Value:
  246. None.
  247. --*/
  248. {
  249. USHORT index;
  250. PCONNECTION connection;
  251. PAGED_CODE( );
  252. ASSERT( ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(SrvEndpointLock)) );
  253. if ( GET_BLOCK_STATE(Endpoint) == BlockStateActive ) {
  254. IF_DEBUG(BLOCK1) SrvPrint1( "Closing endpoint at %p\n", Endpoint );
  255. SET_BLOCK_STATE( Endpoint, BlockStateClosing );
  256. //
  257. // Close all active connections.
  258. //
  259. index = (USHORT)-1;
  260. while ( TRUE ) {
  261. //
  262. // Get the next active connection in the table. If no more
  263. // are available, WalkConnectionTable returns NULL.
  264. // Otherwise, it returns a referenced pointer to a
  265. // connection.
  266. //
  267. connection = WalkConnectionTable( Endpoint, &index );
  268. if ( connection == NULL ) {
  269. break;
  270. }
  271. //
  272. // We don't want to hold the endpoint lock while we close the
  273. // connection (this causes lock level problems). Since we
  274. // already have a referenced pointer to the connection, this
  275. // is safe.
  276. //
  277. RELEASE_LOCK( &SrvEndpointLock );
  278. #if SRVDBG29
  279. UpdateConnectionHistory( "CEND", Endpoint, connection );
  280. #endif
  281. connection->DisconnectReason = DisconnectEndpointClosing;
  282. SrvCloseConnection( connection, FALSE );
  283. ACQUIRE_LOCK( &SrvEndpointLock );
  284. SrvDereferenceConnection( connection );
  285. }
  286. //
  287. // Close all free connections.
  288. //
  289. EmptyFreeConnectionList( Endpoint );
  290. //
  291. // We don't need to hold the endpoint lock anymore.
  292. //
  293. RELEASE_LOCK( &SrvEndpointLock );
  294. //
  295. // Close the endpoint file handle. This causes all pending
  296. // requests to be aborted. It also deregisters all event
  297. // handlers.
  298. //
  299. // *** Note that we have a separate reference to the file
  300. // object, in addition to the handle. We don't release that
  301. // reference until all activity on the endpoint has ceased
  302. // (in SrvDereferenceEndpoint).
  303. //
  304. SRVDBG_RELEASE_HANDLE( Endpoint->EndpointHandle, "END", 2, Endpoint );
  305. SrvNtClose( Endpoint->EndpointHandle, FALSE );
  306. if ( Endpoint->IsConnectionless ) {
  307. SRVDBG_RELEASE_HANDLE( Endpoint->NameSocketHandle, "END", 2, Endpoint );
  308. SrvNtClose( Endpoint->NameSocketHandle, FALSE );
  309. }
  310. //
  311. // Dereference the endpoint (to indicate that it's no longer
  312. // open).
  313. //
  314. SrvDereferenceEndpoint( Endpoint );
  315. INCREMENT_DEBUG_STAT( SrvDbgStatistics.EndpointInfo.Closes );
  316. } else {
  317. RELEASE_LOCK( &SrvEndpointLock );
  318. }
  319. return;
  320. } // SrvCloseEndpoint
  321. VOID SRVFASTCALL
  322. SrvDereferenceEndpoint (
  323. IN PENDPOINT Endpoint
  324. )
  325. /*++
  326. Routine Description:
  327. This function decrements the reference count on an endpoint. If the
  328. reference count goes to zero, the endpoint block is deleted.
  329. Arguments:
  330. Endpoint - Address of endpoint
  331. Return Value:
  332. None.
  333. --*/
  334. {
  335. ULONG newEndpointCount;
  336. PAGED_CODE( );
  337. //
  338. // Enter a critical section and decrement the reference count on the
  339. // block.
  340. //
  341. ACQUIRE_LOCK( &SrvEndpointLock );
  342. IF_DEBUG(REFCNT) {
  343. SrvPrint2( "Dereferencing endpoint %p; old refcnt %lx\n",
  344. Endpoint, Endpoint->BlockHeader.ReferenceCount );
  345. }
  346. ASSERT( GET_BLOCK_TYPE( Endpoint ) == BlockTypeEndpoint );
  347. ASSERT( (LONG)Endpoint->BlockHeader.ReferenceCount > 0 );
  348. UPDATE_REFERENCE_HISTORY( Endpoint, TRUE );
  349. if ( --Endpoint->BlockHeader.ReferenceCount == 0 ) {
  350. //
  351. // The new reference count is 0, meaning that it's time to
  352. // delete this block.
  353. //
  354. ASSERT( GET_BLOCK_STATE(Endpoint) != BlockStateActive );
  355. //
  356. // Decrement the count of endpoints in the server. If the new
  357. // count is zero, set the endpoint event.
  358. //
  359. ASSERT( SrvEndpointCount >= 1 );
  360. newEndpointCount = --SrvEndpointCount;
  361. if ( newEndpointCount == 0 ) {
  362. KeSetEvent( &SrvEndpointEvent, 0, FALSE );
  363. }
  364. RELEASE_LOCK( &SrvEndpointLock );
  365. //
  366. // Remove the endpoint from the global list of endpoints.
  367. //
  368. SrvRemoveEntryOrderedList( &SrvEndpointList, Endpoint );
  369. //
  370. // Dereference the file object pointer. (The handle to the file
  371. // object was closed in SrvCloseEndpoint.)
  372. //
  373. ObDereferenceObject( Endpoint->FileObject );
  374. if ( Endpoint->IsConnectionless ) {
  375. ObDereferenceObject( Endpoint->NameSocketFileObject );
  376. }
  377. //
  378. // Free the endpoint block's storage.
  379. //
  380. SrvFreeEndpoint( Endpoint );
  381. } else {
  382. RELEASE_LOCK( &SrvEndpointLock );
  383. }
  384. return;
  385. } // SrvDereferenceEndpoint
  386. VOID
  387. SrvFreeEndpoint (
  388. IN PENDPOINT Endpoint
  389. )
  390. /*++
  391. Routine Description:
  392. This function returns an Endpoint Block to the system nonpaged pool.
  393. Arguments:
  394. Endpoint - Address of endpoint
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. PAGED_CODE( );
  400. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Endpoint, BlockTypeGarbage, BlockStateDead, -1 );
  401. DEBUG Endpoint->BlockHeader.ReferenceCount = (ULONG)-1;
  402. TERMINATE_REFERENCE_HISTORY( Endpoint );
  403. if ( Endpoint->IpxMaxPacketSizeArray != NULL ) {
  404. FREE_HEAP( Endpoint->IpxMaxPacketSizeArray );
  405. }
  406. if ( Endpoint->ConnectionTable.Table != NULL ) {
  407. SrvFreeTable( &Endpoint->ConnectionTable );
  408. }
  409. DEALLOCATE_NONPAGED_POOL( Endpoint );
  410. IF_DEBUG(HEAP) SrvPrint1( "SrvFreeEndpoint: Freed endpoint block at %p\n", Endpoint );
  411. INCREMENT_DEBUG_STAT( SrvDbgStatistics.EndpointInfo.Frees );
  412. return;
  413. } // SrvFreeEndpoint
  414. VOID
  415. SrvReferenceEndpoint (
  416. PENDPOINT Endpoint
  417. )
  418. /*++
  419. Routine Description:
  420. This function increments the reference count on an endpoint block.
  421. Arguments:
  422. Endpoint - Address of endpoint
  423. Return Value:
  424. None.
  425. --*/
  426. {
  427. PAGED_CODE( );
  428. //
  429. // Enter a critical section and increment the reference count on the
  430. // endpoint.
  431. //
  432. ACQUIRE_LOCK( &SrvEndpointLock );
  433. ASSERT( (LONG)Endpoint->BlockHeader.ReferenceCount > 0 );
  434. ASSERT( GET_BLOCK_TYPE(Endpoint) == BlockTypeEndpoint );
  435. ASSERT( GET_BLOCK_STATE(Endpoint) == BlockStateActive );
  436. UPDATE_REFERENCE_HISTORY( Endpoint, FALSE );
  437. Endpoint->BlockHeader.ReferenceCount++;
  438. IF_DEBUG(REFCNT) SrvPrint2( "Referencing endpoint %p; new refcnt %lx\n",
  439. Endpoint, Endpoint->BlockHeader.ReferenceCount );
  440. RELEASE_LOCK( &SrvEndpointLock );
  441. return;
  442. } // SrvReferenceEndpoint
  443. BOOLEAN
  444. SrvFindNamedEndpoint(
  445. IN PUNICODE_STRING ServerName,
  446. OUT PBOOLEAN RemapPipeNames OPTIONAL
  447. )
  448. /*++
  449. Routine Description:
  450. This routine returns TRUE of any endpoint is supporting 'ServerName'.
  451. Additionally, set the RemapPipeNames variable from the found endpoint.
  452. --*/
  453. {
  454. PLIST_ENTRY listEntry;
  455. PENDPOINT endpoint = NULL;
  456. PAGED_CODE( );
  457. if( ARGUMENT_PRESENT( RemapPipeNames ) ) {
  458. *RemapPipeNames = FALSE;
  459. }
  460. //
  461. // Find an endpoint block supporting the specified name.
  462. //
  463. ACQUIRE_LOCK_SHARED( &SrvEndpointLock );
  464. for( listEntry = SrvEndpointList.ListHead.Flink;
  465. listEntry != &SrvEndpointList.ListHead;
  466. endpoint = NULL, listEntry = listEntry->Flink ) {
  467. endpoint = CONTAINING_RECORD(
  468. listEntry,
  469. ENDPOINT,
  470. GlobalEndpointListEntry
  471. );
  472. //
  473. // Skip any inappropriate endpoints
  474. //
  475. if( GET_BLOCK_STATE( endpoint ) != BlockStateActive ||
  476. endpoint->IsConnectionless ||
  477. (ARGUMENT_PRESENT( RemapPipeNames ) && endpoint->IsNoNetBios) ) {
  478. continue;
  479. }
  480. //
  481. // See if this endpoint literally matches the name we're looking for
  482. //
  483. if( RtlEqualUnicodeString( ServerName, &endpoint->ServerName, TRUE ) ) {
  484. break;
  485. }
  486. //
  487. // We might have a case where the ServerName is something like
  488. // server.dns.company.com
  489. // but the endpoint netbios name is only 'server'. We should match this
  490. //
  491. if( endpoint->ServerName.Length < ServerName->Length ) {
  492. UNICODE_STRING shortServerName;
  493. shortServerName = *ServerName;
  494. shortServerName.Length = endpoint->ServerName.Length;
  495. if (RtlEqualUnicodeString( &endpoint->ServerName, &shortServerName, TRUE)) {
  496. if (endpoint->ServerName.Length < ((NETBIOS_NAME_LEN - 1) * sizeof(WCHAR))) {
  497. if (ServerName->Buffer[ shortServerName.Length / sizeof( WCHAR ) ] == L'.') {
  498. break;
  499. }
  500. } else {
  501. if (endpoint->ServerName.Length == (NETBIOS_NAME_LEN - 1) * sizeof(WCHAR)) {
  502. break;
  503. }
  504. }
  505. }
  506. }
  507. //
  508. // See if this endpoint domain name literally matches the name we're
  509. // looking for. The following two tests against the domain name are
  510. // required to cover the case when there are certain components that
  511. // use the domain name to talk to the server. Given the way name resolution
  512. // records are setup this used to work before this checkin. This change
  513. // breaks them. These tests provide us the backward compatibility.
  514. //
  515. if( RtlEqualUnicodeString( ServerName, &endpoint->DomainName, TRUE ) ) {
  516. break;
  517. }
  518. //
  519. // We might have a case where the ServerName is something like
  520. // server.dns.company.com
  521. // but the endpoint netbios name is only 'server'. We should match this
  522. //
  523. if( endpoint->DomainName.Length < ServerName->Length ) {
  524. UNICODE_STRING shortServerName;
  525. shortServerName = *ServerName;
  526. shortServerName.Length = endpoint->DomainName.Length;
  527. if (RtlEqualUnicodeString( &endpoint->DomainName, &shortServerName, TRUE)) {
  528. if (endpoint->DomainName.Length <= (NETBIOS_NAME_LEN * sizeof(WCHAR))) {
  529. if (ServerName->Buffer[ shortServerName.Length / sizeof( WCHAR ) ] == L'.') {
  530. break;
  531. }
  532. } else {
  533. if (endpoint->DomainName.Length == (NETBIOS_NAME_LEN - 1) * sizeof(WCHAR)) {
  534. break;
  535. }
  536. }
  537. }
  538. }
  539. }
  540. if( ARGUMENT_PRESENT( RemapPipeNames ) && endpoint != NULL ) {
  541. *RemapPipeNames = ( endpoint->RemapPipeNames == TRUE );
  542. }
  543. RELEASE_LOCK( &SrvEndpointLock );
  544. return endpoint != NULL;
  545. }
  546. VOID
  547. EmptyFreeConnectionList (
  548. IN PENDPOINT Endpoint
  549. )
  550. {
  551. PCONNECTION connection;
  552. PLIST_ENTRY listEntry;
  553. KIRQL oldIrql;
  554. //
  555. // *** In order to synchronize with the TDI connect handler in
  556. // the FSD, which only uses a spin lock to serialize access
  557. // to the free connection list (and does not check the
  558. // endpoint state), we need to atomically capture the list
  559. // head and empty the list.
  560. //
  561. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  562. listEntry = Endpoint->FreeConnectionList.Flink;
  563. InitializeListHead( &Endpoint->FreeConnectionList );
  564. #if SRVDBG29
  565. UpdateConnectionHistory( "CLOS", Endpoint, NULL );
  566. #endif
  567. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  568. while ( listEntry != &Endpoint->FreeConnectionList ) {
  569. connection = CONTAINING_RECORD(
  570. listEntry,
  571. CONNECTION,
  572. EndpointFreeListEntry
  573. );
  574. listEntry = listEntry->Flink;
  575. SrvCloseFreeConnection( connection );
  576. }
  577. return;
  578. } // EmptyFreeConnectionList
  579. PCONNECTION
  580. WalkConnectionTable (
  581. IN PENDPOINT Endpoint,
  582. IN OUT PUSHORT Index
  583. )
  584. {
  585. USHORT i;
  586. PTABLE_HEADER tableHeader;
  587. PCONNECTION connection;
  588. KIRQL oldIrql;
  589. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  590. for ( i = 1; i < ENDPOINT_LOCK_COUNT ; i++ ) {
  591. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  592. }
  593. tableHeader = &Endpoint->ConnectionTable;
  594. for ( i = *Index + 1; i < tableHeader->TableSize; i++ ) {
  595. connection = (PCONNECTION)tableHeader->Table[i].Owner;
  596. if ( (connection != NULL) &&
  597. (GET_BLOCK_STATE(connection) == BlockStateActive) ) {
  598. *Index = i;
  599. SrvReferenceConnectionLocked( connection );
  600. goto exit;
  601. }
  602. }
  603. connection = NULL;
  604. exit:
  605. for ( i = ENDPOINT_LOCK_COUNT-1 ; i > 0 ; i-- ) {
  606. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  607. }
  608. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  609. return connection;
  610. } // WalkConnectionTable