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.

1569 lines
41 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. browsenet.c
  5. Abstract:
  6. Code to manage network requests.
  7. Author:
  8. Larry Osterman (LarryO) 24-Mar-1992
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. CRITICAL_SECTION NetworkCritSect = {0};
  14. LIST_ENTRY
  15. ServicedNetworks = {0};
  16. ULONG
  17. NumberOfServicedNetworks = 0;
  18. NET_API_STATUS
  19. BrDumpNetworksWorker(
  20. IN PNETWORK Network,
  21. IN PVOID Context
  22. );
  23. VOID
  24. BrInitializeNetworks(
  25. VOID
  26. )
  27. /*++
  28. Routine Description:
  29. Initialization for this source file.
  30. Arguments:
  31. None.
  32. Return Value:
  33. Status of operation.
  34. Note: no need to wrap in try-finally since caller is.
  35. --*/
  36. {
  37. InitializeListHead(&ServicedNetworks);
  38. InitializeCriticalSection(&NetworkCritSect);
  39. return;
  40. }
  41. BOOL
  42. BrMapToDirectHost(
  43. IN PUNICODE_STRING InputNetbiosTransportName,
  44. OUT WCHAR DirectHostTransportName[MAX_PATH+1]
  45. )
  46. /*++
  47. Routine Description:
  48. This routine maps from a Netbios transport and the corresponding
  49. direct host transport.
  50. The Netbios transport is PNPed since the redir binds to it. The direct host
  51. transport is not PNPed since the redir doesn't bind to it. This routine
  52. maps from on to the other to allow both transports to be bound from the
  53. same PNP event.
  54. Arguments:
  55. InputNetbiosTransportName - Transport name to map.
  56. DirectHostTransportName - Corresponding mapped transport name
  57. Return Value:
  58. TRUE iff there is a mapped equivalent name.
  59. --*/
  60. {
  61. //
  62. // Only mapp if mapping is configured.
  63. //
  64. EnterCriticalSection(&BrInfo.ConfigCritSect);
  65. if (BrInfo.DirectHostBinding != NULL ) {
  66. LPTSTR_ARRAY TStrArray = BrInfo.DirectHostBinding;
  67. UNICODE_STRING IpxTransportName;
  68. UNICODE_STRING NetbiosTransportName;
  69. while (!NetpIsTStrArrayEmpty(TStrArray)) {
  70. RtlInitUnicodeString(&IpxTransportName, TStrArray);
  71. TStrArray = NetpNextTStrArrayEntry(TStrArray);
  72. ASSERT (!NetpIsTStrArrayEmpty(TStrArray));
  73. if (!NetpIsTStrArrayEmpty(TStrArray)) {
  74. RtlInitUnicodeString(&NetbiosTransportName, TStrArray);
  75. //
  76. // If the current name matches the one passed,
  77. // return the mapped name to the caller.
  78. //
  79. if ( RtlEqualUnicodeString( &NetbiosTransportName,
  80. InputNetbiosTransportName,
  81. TRUE )) {
  82. wcsncpy( DirectHostTransportName,
  83. IpxTransportName.Buffer, MAX_PATH );
  84. LeaveCriticalSection(&BrInfo.ConfigCritSect);
  85. return TRUE;
  86. }
  87. TStrArray = NetpNextTStrArrayEntry(TStrArray);
  88. }
  89. }
  90. }
  91. LeaveCriticalSection(&BrInfo.ConfigCritSect);
  92. return FALSE;
  93. }
  94. NET_API_STATUS
  95. BrCreateNetworks(
  96. PDOMAIN_INFO DomainInfo
  97. )
  98. /*++
  99. Routine Description:
  100. Create all of the networks for a particular domain.
  101. Arguments:
  102. DomainInfo - Specifies the domain being browsed.
  103. Return Value:
  104. Status of operation.
  105. --*/
  106. {
  107. NET_API_STATUS NetStatus;
  108. PLMDR_TRANSPORT_LIST TransportList = NULL ;
  109. PLMDR_TRANSPORT_LIST TransportEntry;
  110. BOOLEAN ConfigCritSectLocked = FALSE;
  111. BrPrint(( BR_NETWORK, "%ws: Creating networks for domain\n", DomainInfo->DomUnicodeDomainName ));
  112. //
  113. // Get the list of transports from the datagram receiver.
  114. //
  115. NetStatus = BrGetTransportList(&TransportList);
  116. if ( NetStatus != NERR_Success ) {
  117. goto Cleanup;
  118. }
  119. //
  120. // Create a Network for each of the transports.
  121. //
  122. TransportEntry = TransportList;
  123. while (TransportEntry != NULL) {
  124. //
  125. // Don't do the Direct Host IPX transport here.
  126. //
  127. if ( (TransportEntry->Flags & LMDR_TRANSPORT_IPX) == 0 ) {
  128. UNICODE_STRING TransportName;
  129. TransportName.Buffer = TransportEntry->TransportName;
  130. TransportName.Length = (USHORT)TransportEntry->TransportNameLength;
  131. //
  132. // We know the bowser sticks in a null at the end, so the max length
  133. // is the length + 1.
  134. //
  135. TransportName.MaximumLength = (USHORT)TransportEntry->TransportNameLength+sizeof(WCHAR);
  136. NetStatus = BrCreateNetwork(
  137. &TransportName,
  138. TransportEntry->Flags,
  139. NULL,
  140. DomainInfo );
  141. if ( NetStatus != NERR_Success ) {
  142. goto Cleanup;
  143. }
  144. }
  145. if (TransportEntry->NextEntryOffset == 0) {
  146. TransportEntry = NULL;
  147. } else {
  148. TransportEntry = (PLMDR_TRANSPORT_LIST)((PCHAR)TransportEntry+TransportEntry->NextEntryOffset);
  149. }
  150. }
  151. NetStatus = NERR_Success;
  152. Cleanup:
  153. if ( ConfigCritSectLocked ) {
  154. LeaveCriticalSection(&BrInfo.ConfigCritSect);
  155. }
  156. if ( TransportList != NULL ) {
  157. MIDL_user_free(TransportList);
  158. }
  159. return NetStatus;
  160. }
  161. NET_API_STATUS
  162. BrCreateNetwork(
  163. IN PUNICODE_STRING TransportName,
  164. IN ULONG TransportFlags,
  165. IN PUNICODE_STRING AlternateTransportName OPTIONAL,
  166. IN PDOMAIN_INFO DomainInfo
  167. )
  168. /*++
  169. Routine Description:
  170. This routine allocates memory to hold a network structure, and initializes
  171. all of its associated data structures.
  172. Arguments:
  173. TransportName - The name of the transport to add.
  174. TransportFlags - Flags describing characteristics of the transport
  175. AlternateTransportName - If specified, this is the name of an alternate
  176. transport similar to the one being created.
  177. DomainInfo - Specifies the domain being browsed.
  178. Return Value:
  179. Status of operation (mostly status of allocations).
  180. --*/
  181. {
  182. NET_API_STATUS NetStatus;
  183. PNETWORK Network;
  184. BOOLEAN NetworkLockInitialized = FALSE;
  185. BOOLEAN ResponseCacheLockInitialized = FALSE;
  186. BOOLEAN CanCallBrDestroyNetwork = FALSE;
  187. BOOLEAN ConfigCritSectLocked = FALSE;
  188. BrPrint(( BR_NETWORK,
  189. "%ws: %ws: Creating network.\n",
  190. DomainInfo->DomUnicodeDomainName,
  191. TransportName->Buffer ));
  192. //
  193. // Check to see if the transport already exists.
  194. //
  195. if ((Network = BrFindNetwork( DomainInfo, TransportName)) != NULL) {
  196. BrDereferenceNetwork( Network );
  197. return NERR_AlreadyExists;
  198. }
  199. //
  200. // If this transport is explicitly on our list of transports to unbind,
  201. // simply ignore the transport.
  202. //
  203. if (BrInfo.UnboundBindings != NULL) {
  204. LPTSTR_ARRAY TStrArray = BrInfo.UnboundBindings;
  205. while (!NetpIsTStrArrayEmpty(TStrArray)) {
  206. LPWSTR NewTransportName;
  207. #define NAME_PREFIX L"\\Device\\"
  208. #define NAME_PREFIX_LENGTH 8
  209. //
  210. // The transport name in the registry is only optionally prefixed with \device\
  211. //
  212. if ( _wcsnicmp( NAME_PREFIX, TStrArray, NAME_PREFIX_LENGTH) == 0 ) {
  213. NewTransportName = TransportName->Buffer;
  214. } else {
  215. NewTransportName = TransportName->Buffer + NAME_PREFIX_LENGTH;
  216. }
  217. if ( _wcsicmp( TStrArray, NewTransportName ) == 0 ) {
  218. BrPrint(( BR_NETWORK, "Binding is marked as unbound: %s (Silently ignoring)\n", TransportName->Buffer ));
  219. return NERR_Success;
  220. }
  221. TStrArray = NetpNextTStrArrayEntry(TStrArray);
  222. }
  223. }
  224. //
  225. // Create the transport.
  226. //
  227. try {
  228. //
  229. // Allocate the NETWORK structure.
  230. //
  231. Network = MIDL_user_allocate(sizeof(NETWORK));
  232. if (Network == NULL) {
  233. try_return(NetStatus = ERROR_NOT_ENOUGH_MEMORY);
  234. }
  235. RtlZeroMemory( Network, sizeof(NETWORK) );
  236. //
  237. // Initialize those fields that must be initialized before we can call
  238. // BrDeleteNetwork (on failure).
  239. //
  240. RtlInitializeResource(&Network->Lock);
  241. NetworkLockInitialized = TRUE;
  242. Network->Role = BrDefaultRole;
  243. // One for being in ServiceNetworks. One for this routine's reference.
  244. Network->ReferenceCount = 2;
  245. Network->NetworkName.Buffer = MIDL_user_allocate(TransportName->MaximumLength);
  246. if (Network->NetworkName.Buffer == NULL) {
  247. try_return(NetStatus = ERROR_NOT_ENOUGH_MEMORY);
  248. }
  249. Network->NetworkName.MaximumLength = TransportName->MaximumLength;
  250. RtlCopyUnicodeString(&Network->NetworkName, TransportName);
  251. Network->NetworkName.Buffer[Network->NetworkName.Length/sizeof(WCHAR)] = UNICODE_NULL;
  252. RtlZeroMemory( Network->UncMasterBrowserName, sizeof( Network->UncMasterBrowserName ));
  253. if ( TransportFlags & LMDR_TRANSPORT_WANNISH ) {
  254. Network->Flags |= NETWORK_WANNISH;
  255. }
  256. if ( TransportFlags & LMDR_TRANSPORT_RAS ) {
  257. Network->Flags |= NETWORK_RAS;
  258. }
  259. if ( TransportFlags & LMDR_TRANSPORT_PDC ) {
  260. Network->Flags |= NETWORK_PDC;
  261. }
  262. InitializeInterimServerList(&Network->BrowseTable,
  263. BrBrowseTableInsertRoutine,
  264. BrBrowseTableUpdateRoutine,
  265. BrBrowseTableDeleteRoutine,
  266. BrBrowseTableAgeRoutine);
  267. Network->LastBowserDomainQueried = 0;
  268. InitializeInterimServerList(&Network->DomainList,
  269. BrDomainTableInsertRoutine,
  270. BrDomainTableUpdateRoutine,
  271. BrDomainTableDeleteRoutine,
  272. BrDomainTableAgeRoutine);
  273. InitializeListHead(&Network->OtherDomainsList);
  274. InitializeCriticalSection(&Network->ResponseCacheLock);
  275. ResponseCacheLockInitialized = TRUE;
  276. InitializeListHead(&Network->ResponseCache);
  277. Network->TimeCacheFlushed = 0;
  278. Network->NumberOfCachedResponses = 0;
  279. EnterCriticalSection(&NetworkCritSect);
  280. Network->DomainInfo = DomainInfo;
  281. DomainInfo->ReferenceCount ++;
  282. InsertHeadList(&ServicedNetworks, &Network->NextNet);
  283. NumberOfServicedNetworks += 1;
  284. //
  285. // Create a worker thread for this network
  286. //
  287. BrWorkerCreateThread( NumberOfServicedNetworks );
  288. LeaveCriticalSection(&NetworkCritSect);
  289. //
  290. // Mark that we can now call BrDeleteNetwork upon failure.
  291. //
  292. // Continue initializing the network.
  293. //
  294. CanCallBrDestroyNetwork = TRUE;
  295. NetStatus = BrCreateTimer(&Network->UpdateAnnouncementTimer);
  296. if (NetStatus != NERR_Success) {
  297. try_return(NetStatus);
  298. }
  299. NetStatus = BrCreateTimer(&Network->BackupBrowserTimer);
  300. if (NetStatus != NERR_Success) {
  301. try_return(NetStatus);
  302. }
  303. NetStatus = BrCreateTimer(&Network->MasterBrowserTimer);
  304. if (NetStatus != NERR_Success) {
  305. try_return(NetStatus);
  306. }
  307. NetStatus = BrCreateTimer(&Network->MasterBrowserAnnouncementTimer);
  308. if (NetStatus != NERR_Success) {
  309. try_return(NetStatus);
  310. }
  311. //
  312. // Handle the alternate transport.
  313. //
  314. if (ARGUMENT_PRESENT(AlternateTransportName)) {
  315. PNETWORK AlternateNetwork = BrFindNetwork( DomainInfo, AlternateTransportName);
  316. //
  317. // If we didn't find an alternate network, or if that network
  318. // already has an alternate network, return an error.
  319. //
  320. if ( AlternateNetwork == NULL ) {
  321. BrPrint(( BR_CRITICAL,
  322. "%ws: %ws: Creating network. Can't find alternate net %ws\n",
  323. DomainInfo->DomUnicodeDomainName,
  324. TransportName->Buffer,
  325. AlternateTransportName ));
  326. try_return(NetStatus = NERR_InternalError);
  327. }
  328. if (AlternateNetwork->AlternateNetwork != NULL) {
  329. BrDereferenceNetwork( AlternateNetwork );
  330. try_return(NetStatus = NERR_InternalError);
  331. }
  332. Network->Flags |= NETWORK_IPX;
  333. //
  334. // Link the two networks together.
  335. //
  336. Network->AlternateNetwork = AlternateNetwork;
  337. AlternateNetwork->AlternateNetwork = Network;
  338. BrDereferenceNetwork( AlternateNetwork );
  339. } else {
  340. Network->AlternateNetwork = NULL;
  341. }
  342. //
  343. // Since the Rdr doesn't support this transport,
  344. // we actually have to bind ourselves.
  345. //
  346. // Bind for Direct host IPX and for emulated domains.
  347. //
  348. if ( (Network->Flags & NETWORK_IPX) || DomainInfo->IsEmulatedDomain ) {
  349. NetStatus = BrBindToTransport( TransportName->Buffer,
  350. DomainInfo->DomUnicodeDomainName,
  351. DomainInfo->DomUnicodeComputerName );
  352. if ( NetStatus != NERR_Success ) {
  353. BrPrint(( BR_CRITICAL,
  354. "%ws: %ws: Creating network. Can't bind to transport\n",
  355. DomainInfo->DomUnicodeDomainName,
  356. TransportName->Buffer ));
  357. try_return( NetStatus );
  358. }
  359. Network->Flags |= NETWORK_BOUND;
  360. }
  361. //
  362. // Post a WaitForRoleChange FsControl on each network the bowser
  363. // driver supports. This FsControl will complete when a "tickle"
  364. // packet is received on the machine, or when a master browser loses
  365. // an election.
  366. //
  367. NetStatus = PostWaitForRoleChange(Network);
  368. if (NetStatus != NERR_Success) {
  369. BrPrint(( BR_CRITICAL,
  370. "%ws: %ws: Creating network. Can't post wait for role change: %ld\n",
  371. DomainInfo->DomUnicodeDomainName,
  372. TransportName->Buffer,
  373. NetStatus ));
  374. try_return(NetStatus);
  375. }
  376. EnterCriticalSection(&BrInfo.ConfigCritSect);
  377. ConfigCritSectLocked = TRUE;
  378. //
  379. // If MaintainServerList says to automatically determine mastership,
  380. // post queryies to the driver.
  381. //
  382. if (BrInfo.MaintainServerList == 0) {
  383. //
  384. // Post a BecomeBackup FsControl API on each network the bowser
  385. // driver supports. This FsControl will complete when the master
  386. // for the net wants this client to become a backup server.
  387. //
  388. NetStatus = PostBecomeBackup( Network );
  389. if (NetStatus != NERR_Success) {
  390. BrPrint(( BR_CRITICAL,
  391. "%ws: %ws: Creating network. Can't post become backup.\n",
  392. DomainInfo->DomUnicodeDomainName,
  393. TransportName->Buffer,
  394. NetStatus ));
  395. try_return(NetStatus);
  396. }
  397. //
  398. // Post a BecomeMaster FsControl on each network the bowser driver
  399. // supports. This FsControl will complete when this machine becomes
  400. // a master browser server.
  401. //
  402. NetStatus = PostBecomeMaster( Network );
  403. if (NetStatus != NERR_Success) {
  404. BrPrint(( BR_CRITICAL,
  405. "%ws: %ws: Creating network. Can't post become master.\n",
  406. DomainInfo->DomUnicodeDomainName,
  407. TransportName->Buffer,
  408. NetStatus ));
  409. try_return(NetStatus);
  410. }
  411. }
  412. //
  413. // If this machine is running as domain master browser server, post an
  414. // FsControl to retreive master browser announcements.
  415. //
  416. if ( Network->Flags & NETWORK_PDC ) {
  417. NetStatus = PostGetMasterAnnouncement ( Network );
  418. if (NetStatus != NERR_Success) {
  419. BrPrint(( BR_CRITICAL,
  420. "%ws: %ws: Creating network. Can't post get master announcment.\n",
  421. DomainInfo->DomUnicodeDomainName,
  422. TransportName->Buffer,
  423. NetStatus ));
  424. // This isn't fatal. We automatically try again later.
  425. } else {
  426. BrPrint(( BR_NETWORK, "%ws: %ws: GetMasterAnnouncement posted.\n",
  427. DomainInfo->DomUnicodeDomainName,
  428. TransportName->Buffer ));
  429. }
  430. }
  431. //
  432. // If we are on either a domain master, or on a lanman/NT machine,
  433. // force an election on all our transports to make sure that we're
  434. // the master
  435. //
  436. if ( (Network->Flags & NETWORK_PDC) != 0 || BrInfo.IsLanmanNt) {
  437. NetStatus = BrElectMasterOnNet( Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_LANMAN_NT_STARTED );
  438. if (NetStatus != NERR_Success) {
  439. BrPrint(( BR_CRITICAL,
  440. "%ws: %ws: Creating network. Can't Elect Master.\n",
  441. DomainInfo->DomUnicodeDomainName,
  442. TransportName->Buffer,
  443. NetStatus ));
  444. // This isn't fatal.
  445. } else {
  446. BrPrint(( BR_NETWORK, "%ws: %ws: Election forced on startup.\n",
  447. DomainInfo->DomUnicodeDomainName,
  448. TransportName->Buffer ));
  449. }
  450. }
  451. //
  452. // This machine's browser has MaintainServerList set to either 0 or 1.
  453. //
  454. //
  455. // If MaintainServerList = Auto,
  456. // then asynchronously get the master server name for each network
  457. // to ensure someone is the master.
  458. //
  459. // Ignore failures since this is just priming the domain.
  460. //
  461. EnterCriticalSection(&BrInfo.ConfigCritSect);
  462. if (BrInfo.MaintainServerList == 0) {
  463. BrGetMasterServerNameAysnc( Network );
  464. BrPrint(( BR_NETWORK, "%ws: %ws: Find Master queued.\n",
  465. DomainInfo->DomUnicodeDomainName,
  466. TransportName->Buffer ));
  467. //
  468. // if we're a Lan Manager/NT machine, then we need to always be a backup
  469. // browser.
  470. //
  471. //
  472. // MaintainServerList == 1 means Yes
  473. //
  474. } else if (BrInfo.MaintainServerList == 1){
  475. //
  476. // Become a backup server now.
  477. //
  478. NetStatus = BrBecomeBackup( Network );
  479. if (NetStatus != NERR_Success) {
  480. BrPrint(( BR_CRITICAL,
  481. "%ws: %ws: Creating network. Can't BecomeBackup.\n",
  482. DomainInfo->DomUnicodeDomainName,
  483. TransportName->Buffer,
  484. NetStatus ));
  485. // This isn't fatal.
  486. } else {
  487. BrPrint(( BR_NETWORK, "%ws: %ws: Became Backup.\n",
  488. DomainInfo->DomUnicodeDomainName,
  489. TransportName->Buffer ));
  490. }
  491. }
  492. LeaveCriticalSection(&BrInfo.ConfigCritSect);
  493. //
  494. // If this isn't already an alternate transport,
  495. // and there is a configured alternate transport for this transport,
  496. // create the alternate transport now.
  497. //
  498. if (!ARGUMENT_PRESENT(AlternateTransportName)) {
  499. WCHAR DirectHostName[MAX_PATH+1];
  500. UNICODE_STRING DirectHostNameString;
  501. if ( BrMapToDirectHost( TransportName, DirectHostName ) ) {
  502. RtlInitUnicodeString(&DirectHostNameString, DirectHostName );
  503. BrPrint(( BR_NETWORK, "%ws: %ws: Try adding alternate transport %ws.\n",
  504. DomainInfo->DomUnicodeDomainName,
  505. TransportName->Buffer,
  506. DirectHostName ));
  507. //
  508. // There is a direct host binding on this machine. We want to add
  509. // the direct host transport to the browser.
  510. //
  511. NetStatus = BrCreateNetwork(
  512. &DirectHostNameString,
  513. 0, // No special flags
  514. TransportName,
  515. DomainInfo );
  516. if (NetStatus != NERR_Success) {
  517. BrPrint(( BR_CRITICAL, "%ws: %ws: Couldn't add alternate transport %ws. %ld\n",
  518. DomainInfo->DomUnicodeDomainName,
  519. TransportName->Buffer,
  520. DirectHostName,
  521. NetStatus ));
  522. try_return(NetStatus);
  523. }
  524. }
  525. }
  526. NetStatus = NERR_Success;
  527. try_exit:NOTHING;
  528. } finally {
  529. if ( AbnormalTermination() ) {
  530. NetStatus = NERR_InternalError;
  531. }
  532. if ( ConfigCritSectLocked ) {
  533. LeaveCriticalSection(&BrInfo.ConfigCritSect);
  534. ConfigCritSectLocked = FALSE;
  535. }
  536. if (NetStatus != NERR_Success) {
  537. if (Network != NULL) {
  538. //
  539. // If we've initialized to the point where we can call
  540. // we can call BrDeleteNetwork, do so.
  541. //
  542. if ( CanCallBrDestroyNetwork ) {
  543. (VOID) BrDeleteNetwork( Network, NULL );
  544. //
  545. // Otherwise, just delete what we've created.
  546. //
  547. } else {
  548. if (ResponseCacheLockInitialized) {
  549. DeleteCriticalSection(&Network->ResponseCacheLock);
  550. }
  551. if (NetworkLockInitialized) {
  552. RtlDeleteResource(&Network->Lock);
  553. }
  554. if (Network->NetworkName.Buffer != NULL) {
  555. MIDL_user_free(Network->NetworkName.Buffer);
  556. }
  557. MIDL_user_free(Network);
  558. }
  559. }
  560. //
  561. // We're done creating the network.
  562. // Remove this routines reference to it.
  563. //
  564. } else {
  565. BrDereferenceNetwork( Network );
  566. }
  567. }
  568. return NetStatus;
  569. }
  570. VOID
  571. BrUninitializeNetworks(
  572. IN DWORD BrInitState
  573. )
  574. {
  575. DeleteCriticalSection(&NetworkCritSect);
  576. NumberOfServicedNetworks = 0;
  577. }
  578. PNETWORK
  579. BrReferenceNetwork(
  580. PNETWORK PotentialNetwork
  581. )
  582. /*++
  583. Routine Description:
  584. This routine will look up a network given a potential pointer to the network.
  585. This routine is useful if a caller has a pointer to a network but
  586. hasn't incremented the reference count. For instance,
  587. BrIssueAsyncBrowserIoControl calls the async completion routines like that.
  588. Arguments:
  589. PotentialNetwork - Pointer to the network structure to be verified.
  590. Return Value:
  591. NULL - No such network exists
  592. A pointer to the network found. The found network should be dereferenced
  593. using BrDereferenceNetwork.
  594. --*/
  595. {
  596. NTSTATUS Status;
  597. PLIST_ENTRY NetEntry;
  598. EnterCriticalSection(&NetworkCritSect);
  599. for (NetEntry = ServicedNetworks.Flink ;
  600. NetEntry != &ServicedNetworks;
  601. NetEntry = NetEntry->Flink ) {
  602. PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
  603. if ( PotentialNetwork == Network ) {
  604. Network->ReferenceCount ++;
  605. BrPrint(( BR_LOCKS,
  606. "%ws: %ws: reference network: %ld\n",
  607. Network->DomainInfo->DomUnicodeDomainName,
  608. Network->NetworkName.Buffer,
  609. Network->ReferenceCount ));
  610. LeaveCriticalSection(&NetworkCritSect);
  611. return Network;
  612. }
  613. }
  614. LeaveCriticalSection(&NetworkCritSect);
  615. return NULL;
  616. }
  617. VOID
  618. BrDereferenceNetwork(
  619. IN PNETWORK Network
  620. )
  621. /*++
  622. Routine Description:
  623. This routine decrements the reference to a network. If the network reference
  624. count goes to 0, remove the network.
  625. On entry, the global NetworkCritSect crit sect may not be locked
  626. Arguments:
  627. Network - The network to dereference
  628. Return Value:
  629. None
  630. --*/
  631. {
  632. NTSTATUS Status;
  633. ULONG ReferenceCount;
  634. EnterCriticalSection(&NetworkCritSect);
  635. ReferenceCount = -- Network->ReferenceCount;
  636. LeaveCriticalSection(&NetworkCritSect);
  637. BrPrint(( BR_LOCKS,
  638. "%ws: %ws: Dereference network: %ld\n",
  639. Network->DomainInfo->DomUnicodeDomainName,
  640. Network->NetworkName.Buffer,
  641. ReferenceCount ));
  642. if ( ReferenceCount != 0 ) {
  643. return;
  644. }
  645. //
  646. // The alternate network still has a pointer to this network,
  647. // ditch it.
  648. //
  649. if ( Network->AlternateNetwork != NULL ) {
  650. Network->AlternateNetwork->AlternateNetwork = NULL;
  651. }
  652. //
  653. // Tell everyone that this net is going away.
  654. //
  655. BrShutdownBrowserForNet( Network, NULL );
  656. //
  657. // If this service did the bind, do the unbind.
  658. //
  659. // True for IPX and for emulated domains.
  660. //
  661. if (Network->Flags & NETWORK_BOUND) {
  662. NET_API_STATUS NetStatus;
  663. NetStatus = BrUnbindFromTransport( Network->NetworkName.Buffer,
  664. Network->DomainInfo->DomUnicodeDomainName );
  665. if (NetStatus != NERR_Success) {
  666. BrPrint(( BR_CRITICAL,
  667. "%ws: %ws: Unable to unbind from IPX transport\n",
  668. Network->DomainInfo->DomUnicodeDomainName,
  669. Network->NetworkName.Buffer ));
  670. }
  671. }
  672. UninitializeInterimServerList(&Network->BrowseTable);
  673. UninitializeInterimServerList(&Network->DomainList);
  674. if (Network->BackupServerList != NULL) {
  675. MIDL_user_free(Network->BackupServerList);
  676. }
  677. if (Network->BackupDomainList != NULL) {
  678. MIDL_user_free(Network->BackupDomainList);
  679. }
  680. if (Network->NetworkName.Buffer != NULL) {
  681. MIDL_user_free(Network->NetworkName.Buffer);
  682. }
  683. RtlDeleteResource(&Network->Lock);
  684. BrDestroyResponseCache(Network);
  685. DeleteCriticalSection(&Network->ResponseCacheLock);
  686. BrDereferenceDomain( Network->DomainInfo );
  687. MIDL_user_free(Network);
  688. return;
  689. }
  690. NET_API_STATUS
  691. BrDeleteNetwork(
  692. IN PNETWORK Network,
  693. IN PVOID Context
  694. )
  695. /*++
  696. Routine Description:
  697. This routine prevents any new references to the network. It then removes
  698. the global reference to the Network allowing it to be deleted.
  699. Finally, it sleeps until the only reference left is the one held by the caller.
  700. This ensures the Network will be deleted when the caller Dereferences the
  701. network.
  702. Arguments:
  703. Network - The network to remove
  704. The caller must have a reference to the Network.
  705. Context - not used.
  706. Return Value:
  707. NERR_Success - always
  708. --*/
  709. {
  710. BrPrint(( BR_NETWORK,
  711. "%ws: %ws: Delete network\n",
  712. Network->DomainInfo->DomUnicodeDomainName,
  713. Network->NetworkName.Buffer ));
  714. //
  715. // Remove this network from the list to prevent any new references.
  716. //
  717. EnterCriticalSection(&NetworkCritSect);
  718. RemoveEntryList(&Network->NextNet);
  719. NumberOfServicedNetworks -= 1;
  720. LeaveCriticalSection(&NetworkCritSect);
  721. //
  722. // Prevent new references by the timer routines
  723. //
  724. BrDestroyTimer(&Network->MasterBrowserAnnouncementTimer);
  725. BrDestroyTimer(&Network->MasterBrowserTimer);
  726. BrDestroyTimer(&Network->BackupBrowserTimer);
  727. BrDestroyTimer(&Network->UpdateAnnouncementTimer);
  728. //
  729. // Decrement the global reference due to being is 'ServicedNetworks'
  730. //
  731. BrDereferenceNetwork( Network );
  732. //
  733. // Loop until the caller has the last reference.
  734. //
  735. EnterCriticalSection(&NetworkCritSect);
  736. while ( Network->ReferenceCount != 1 ) {
  737. LeaveCriticalSection(&NetworkCritSect);
  738. Sleep(1000);
  739. EnterCriticalSection(&NetworkCritSect);
  740. }
  741. LeaveCriticalSection(&NetworkCritSect);
  742. UNREFERENCED_PARAMETER(Context);
  743. return NERR_Success;
  744. }
  745. PNETWORK
  746. BrFindNetwork(
  747. PDOMAIN_INFO DomainInfo,
  748. PUNICODE_STRING TransportName
  749. )
  750. /*++
  751. Routine Description:
  752. This routine will look up a network given a name.
  753. Arguments:
  754. DomainInfo - Specifies the domain this network is specific to
  755. TransportName - The name of the transport to look up.
  756. Return Value:
  757. NULL - No such network exists
  758. A pointer to the network found. The found network should be dereferenced
  759. using BrDereferenceNetwork.
  760. --*/
  761. {
  762. NTSTATUS Status;
  763. PLIST_ENTRY NetEntry;
  764. EnterCriticalSection(&NetworkCritSect);
  765. for (NetEntry = ServicedNetworks.Flink ;
  766. NetEntry != &ServicedNetworks;
  767. NetEntry = NetEntry->Flink ) {
  768. PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
  769. if ( Network->DomainInfo == DomainInfo &&
  770. RtlEqualUnicodeString(&Network->NetworkName, TransportName, TRUE)) {
  771. Network->ReferenceCount ++;
  772. BrPrint(( BR_LOCKS,
  773. "%ws: %ws: find network: %ld\n",
  774. Network->DomainInfo->DomUnicodeDomainName,
  775. Network->NetworkName.Buffer,
  776. Network->ReferenceCount ));
  777. LeaveCriticalSection(&NetworkCritSect);
  778. return Network;
  779. }
  780. }
  781. LeaveCriticalSection(&NetworkCritSect);
  782. return NULL;
  783. }
  784. PNETWORK
  785. BrFindWannishMasterBrowserNetwork(
  786. PDOMAIN_INFO DomainInfo
  787. )
  788. /*++
  789. Routine Description:
  790. This routine will look up a network that is running IP and is
  791. a master browser.
  792. Arguments:
  793. DomainInfo - Specifies the domain this network is specific to
  794. Return Value:
  795. NULL - No such network exists
  796. A pointer to the network found. The found network should be dereferenced
  797. using BrDereferenceNetwork.
  798. --*/
  799. {
  800. NTSTATUS Status;
  801. PLIST_ENTRY NetEntry;
  802. EnterCriticalSection(&NetworkCritSect);
  803. for (NetEntry = ServicedNetworks.Flink ;
  804. NetEntry != &ServicedNetworks;
  805. NetEntry = NetEntry->Flink ) {
  806. PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
  807. //
  808. // Find a network that is:
  809. // for this domain, and
  810. // is wannish, and
  811. // is a master browser.
  812. //
  813. if ( Network->DomainInfo == DomainInfo &&
  814. (Network->Flags & NETWORK_WANNISH) != 0 &&
  815. (Network->Role & ROLE_MASTER) != 0 ) {
  816. Network->ReferenceCount ++;
  817. BrPrint(( BR_LOCKS,
  818. "%ws: %ws: find wannish master network: %ld\n",
  819. Network->DomainInfo->DomUnicodeDomainName,
  820. Network->NetworkName.Buffer,
  821. Network->ReferenceCount ));
  822. LeaveCriticalSection(&NetworkCritSect);
  823. return Network;
  824. }
  825. }
  826. LeaveCriticalSection(&NetworkCritSect);
  827. return NULL;
  828. }
  829. NET_API_STATUS
  830. BrEnumerateNetworks(
  831. PNET_ENUM_CALLBACK Callback,
  832. PVOID Context
  833. )
  834. /*++
  835. Routine Description:
  836. This routine enumerates all the networks and calls back the specified
  837. callback routine with the specified context.
  838. Arguments:
  839. Callback - The callback routine to call.
  840. Context - Context for the routine.
  841. Return Value:
  842. Status of operation (mostly status of allocations).
  843. --*/
  844. {
  845. NET_API_STATUS NetStatus = NERR_Success;
  846. PLIST_ENTRY NetEntry;
  847. PNETWORK Network;
  848. PNETWORK NetworkToDereference = NULL;
  849. EnterCriticalSection(&NetworkCritSect);
  850. for (NetEntry = ServicedNetworks.Flink ;
  851. NetEntry != &ServicedNetworks;
  852. NetEntry = NetEntry->Flink ) {
  853. //
  854. // Reference the next network in the list
  855. //
  856. Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
  857. Network->ReferenceCount ++;
  858. BrPrint(( BR_LOCKS,
  859. "%ws: %ws: enumerate network: %ld\n",
  860. Network->DomainInfo->DomUnicodeDomainName,
  861. Network->NetworkName.Buffer,
  862. Network->ReferenceCount ));
  863. LeaveCriticalSection(&NetworkCritSect);
  864. //
  865. // Dereference any network previously referenced.
  866. //
  867. if ( NetworkToDereference != NULL) {
  868. BrDereferenceNetwork( NetworkToDereference );
  869. NetworkToDereference = NULL;
  870. }
  871. //
  872. // Call into the callback routine with this network.
  873. //
  874. NetStatus = (Callback)(Network, Context);
  875. EnterCriticalSection(&NetworkCritSect);
  876. NetworkToDereference = Network;
  877. if (NetStatus != NERR_Success) {
  878. break;
  879. }
  880. }
  881. LeaveCriticalSection(&NetworkCritSect);
  882. //
  883. // Dereference the last network
  884. //
  885. if ( NetworkToDereference != NULL) {
  886. BrDereferenceNetwork( NetworkToDereference );
  887. }
  888. return NetStatus;
  889. }
  890. NET_API_STATUS
  891. BrEnumerateNetworksForDomain(
  892. PDOMAIN_INFO DomainInfo OPTIONAL,
  893. PNET_ENUM_CALLBACK Callback,
  894. PVOID Context
  895. )
  896. /*++
  897. Routine Description:
  898. This routine enumerates all the networks for a specified domain
  899. and calls back the specified callback routine with the specified context.
  900. Arguments:
  901. DomainInfo - Specifies the Domain to limit the enumeration to.
  902. NULL implies the primary domain.
  903. Callback - The callback routine to call.
  904. Context - Context for the routine.
  905. Return Value:
  906. Status of operation (mostly status of allocations).
  907. --*/
  908. {
  909. NTSTATUS NetStatus = NERR_Success;
  910. PLIST_ENTRY NetEntry;
  911. PNETWORK Network;
  912. PNETWORK NetworkToDereference = NULL;
  913. //
  914. // Default to the primary domain.
  915. //
  916. if ( DomainInfo == NULL && !IsListEmpty( &ServicedDomains ) ) {
  917. DomainInfo = CONTAINING_RECORD(ServicedDomains.Flink, DOMAIN_INFO, Next);
  918. }
  919. EnterCriticalSection(&NetworkCritSect);
  920. for (NetEntry = ServicedNetworks.Flink ;
  921. NetEntry != &ServicedNetworks;
  922. NetEntry = NetEntry->Flink ) {
  923. //
  924. // If the entry isn't for the specified domain,
  925. // skip it.
  926. //
  927. Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
  928. if ( Network->DomainInfo != DomainInfo ) {
  929. continue;
  930. }
  931. //
  932. // Reference the next network in the list
  933. //
  934. Network->ReferenceCount ++;
  935. BrPrint(( BR_LOCKS,
  936. "%ws: %ws: enumerate network for domain: %ld\n",
  937. Network->DomainInfo->DomUnicodeDomainName,
  938. Network->NetworkName.Buffer,
  939. Network->ReferenceCount ));
  940. LeaveCriticalSection(&NetworkCritSect);
  941. //
  942. // Dereference any network previously referenced.
  943. //
  944. if ( NetworkToDereference != NULL) {
  945. BrDereferenceNetwork( NetworkToDereference );
  946. NetworkToDereference = NULL;
  947. }
  948. //
  949. // Call into the callback routine with this network.
  950. //
  951. NetStatus = (Callback)(Network, Context);
  952. EnterCriticalSection(&NetworkCritSect);
  953. NetworkToDereference = Network;
  954. if (NetStatus != NERR_Success) {
  955. break;
  956. }
  957. }
  958. LeaveCriticalSection(&NetworkCritSect);
  959. //
  960. // Dereference the last network
  961. //
  962. if ( NetworkToDereference != NULL) {
  963. BrDereferenceNetwork( NetworkToDereference );
  964. }
  965. return NERR_Success;
  966. }
  967. #if DBG
  968. BOOL
  969. BrLockNetwork(
  970. IN PNETWORK Network,
  971. IN PCHAR FileName,
  972. IN ULONG LineNumber
  973. )
  974. {
  975. PCHAR File;
  976. File = strrchr(FileName, '\\');
  977. if (File == NULL) {
  978. File = FileName;
  979. }
  980. BrPrint(( BR_LOCKS,
  981. "%ws: %ws: Acquiring network lock %s:%d\n",
  982. Network->DomainInfo->DomUnicodeDomainName,
  983. Network->NetworkName.Buffer,
  984. File,
  985. LineNumber ));
  986. if (!RtlAcquireResourceExclusive(&(Network)->Lock, TRUE)) {
  987. BrPrint(( BR_CRITICAL,
  988. "%ws: %ws: Failed to acquire network %s:%d\n",
  989. Network->DomainInfo->DomUnicodeDomainName,
  990. Network->NetworkName.Buffer,
  991. File, LineNumber ));
  992. return FALSE;
  993. } else {
  994. InterlockedIncrement( &Network->LockCount );
  995. BrPrint(( BR_LOCKS,
  996. "%ws: %ws: network lock %s:%d acquired\n",
  997. Network->DomainInfo->DomUnicodeDomainName,
  998. Network->NetworkName.Buffer,
  999. File, LineNumber ));
  1000. }
  1001. return TRUE;
  1002. }
  1003. BOOL
  1004. BrLockNetworkShared(
  1005. IN PNETWORK Network,
  1006. IN PCHAR FileName,
  1007. IN ULONG LineNumber
  1008. )
  1009. {
  1010. PCHAR File;
  1011. File = strrchr(FileName, '\\');
  1012. if (File == NULL) {
  1013. File = FileName;
  1014. }
  1015. BrPrint(( BR_LOCKS,
  1016. "%ws: %ws: Acquiring network lock %s:%d\n",
  1017. Network->DomainInfo->DomUnicodeDomainName,
  1018. Network->NetworkName.Buffer,
  1019. File, LineNumber ));
  1020. if (!RtlAcquireResourceShared(&(Network)->Lock, TRUE)) {
  1021. BrPrint(( BR_CRITICAL,
  1022. "%ws: %ws: failed to acquire network lock %s:%d\n",
  1023. Network->DomainInfo->DomUnicodeDomainName,
  1024. Network->NetworkName.Buffer,
  1025. File, LineNumber ));
  1026. return FALSE;
  1027. } else {
  1028. // Use InterlockedIncrement since we only have a shared lock on the
  1029. // resource.
  1030. InterlockedIncrement( &Network->LockCount );
  1031. BrPrint(( BR_LOCKS,
  1032. "%ws: %ws: Network lock %s:%d acquired\n",
  1033. Network->DomainInfo->DomUnicodeDomainName,
  1034. Network->NetworkName.Buffer,
  1035. File, LineNumber ));
  1036. }
  1037. return TRUE;
  1038. }
  1039. VOID
  1040. BrUnlockNetwork(
  1041. IN PNETWORK Network,
  1042. IN PCHAR FileName,
  1043. IN ULONG LineNumber
  1044. )
  1045. {
  1046. PCHAR File;
  1047. LONG ReturnValue;
  1048. File = strrchr(FileName, '\\');
  1049. if (File == NULL) {
  1050. File = FileName;
  1051. }
  1052. BrPrint(( BR_LOCKS,
  1053. "%ws: %ws: Releasing network lock %s:%d\n",
  1054. Network->DomainInfo->DomUnicodeDomainName,
  1055. Network->NetworkName.Buffer,
  1056. File, LineNumber ));
  1057. //
  1058. // Decrement the lock count.
  1059. //
  1060. ReturnValue = InterlockedDecrement( &Network->LockCount );
  1061. if ( ReturnValue < 0) {
  1062. BrPrint(( BR_CRITICAL,
  1063. "%ws: %ws: Over released network lock %s:%d\n",
  1064. Network->DomainInfo->DomUnicodeDomainName,
  1065. Network->NetworkName.Buffer,
  1066. File, LineNumber ));
  1067. }
  1068. RtlReleaseResource(&(Network)->Lock);
  1069. return;
  1070. }
  1071. #endif
  1072. #if DBG
  1073. VOID
  1074. BrDumpNetworks(
  1075. VOID
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. This routine will dump the contents of each of the browser network
  1080. structures.
  1081. Arguments:
  1082. None.
  1083. Return Value:
  1084. None.
  1085. --*/
  1086. {
  1087. BrEnumerateNetworks(BrDumpNetworksWorker, NULL);
  1088. }
  1089. NET_API_STATUS
  1090. BrDumpNetworksWorker(
  1091. IN PNETWORK Network,
  1092. IN PVOID Context
  1093. )
  1094. {
  1095. if (!LOCK_NETWORK(Network)) {
  1096. return NERR_InternalError;
  1097. }
  1098. BrPrint(( BR_CRITICAL,
  1099. "%ws: %ws: Network at %lx\n",
  1100. Network->DomainInfo->DomUnicodeDomainName,
  1101. Network->NetworkName.Buffer,
  1102. Network ));
  1103. BrPrint(( BR_CRITICAL, " Reference Count: %lx\n", Network->ReferenceCount));
  1104. BrPrint(( BR_CRITICAL, " Flags: %lx\n", Network->Flags));
  1105. BrPrint(( BR_CRITICAL, " Role: %lx\n", Network->Role));
  1106. BrPrint(( BR_CRITICAL, " Master Browser Name: %ws\n", Network->UncMasterBrowserName ));
  1107. UNLOCK_NETWORK(Network);
  1108. return(NERR_Success);
  1109. }
  1110. #endif