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.

1083 lines
33 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. bowelect.c
  5. Abstract:
  6. This module implements all of the election related routines for the NT
  7. browser
  8. Author:
  9. Larry Osterman (LarryO) 21-Jun-1990
  10. Revision History:
  11. 21-Jun-1990 LarryO
  12. Created
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #define INCLUDE_SMB_TRANSACTION
  17. NTSTATUS
  18. BowserStartElection(
  19. IN PTRANSPORT Transport
  20. );
  21. LONG
  22. BowserSetElectionCriteria(
  23. IN PPAGED_TRANSPORT Transport
  24. );
  25. NTSTATUS
  26. BowserElectMaster(
  27. IN PTRANSPORT Transport
  28. );
  29. VOID
  30. HandleElectionWorker(
  31. IN PVOID Ctx
  32. );
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text(PAGE, GetMasterName)
  35. #pragma alloc_text(PAGE, HandleElectionWorker)
  36. #pragma alloc_text(PAGE, BowserSetElectionCriteria)
  37. #pragma alloc_text(PAGE, BowserStartElection)
  38. #pragma alloc_text(PAGE, BowserElectMaster)
  39. #pragma alloc_text(PAGE, BowserLoseElection)
  40. #pragma alloc_text(PAGE, BowserFindMaster)
  41. #pragma alloc_text(PAGE, BowserSendElection)
  42. #endif
  43. NTSTATUS
  44. GetMasterName (
  45. IN PIRP Irp,
  46. IN BOOLEAN Wait,
  47. IN BOOLEAN InFsd,
  48. IN PLMDR_REQUEST_PACKET InputBuffer,
  49. IN ULONG InputBufferLength
  50. )
  51. {
  52. NTSTATUS Status;
  53. PTRANSPORT Transport = NULL;
  54. PPAGED_TRANSPORT PagedTransport;
  55. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  56. PAGED_CODE();
  57. try {
  58. WCHAR TransportNameBuffer[MAX_PATH+1];
  59. WCHAR DomainNameBuffer[DNLEN+1];
  60. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  61. (ULONG)FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.GetMasterName.Name)+3*sizeof(WCHAR)) {
  62. try_return(Status = STATUS_INVALID_PARAMETER);
  63. }
  64. if (InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) {
  65. try_return(Status = STATUS_INVALID_PARAMETER);
  66. }
  67. CAPTURE_UNICODE_STRING( &InputBuffer->TransportName, TransportNameBuffer );
  68. CAPTURE_UNICODE_STRING( &InputBuffer->EmulatedDomainName, DomainNameBuffer );
  69. Transport = BowserFindTransport(&InputBuffer->TransportName, &InputBuffer->EmulatedDomainName );
  70. dprintf(DPRT_REF, ("Called Find transport %lx from GetMasterName.\n", Transport));
  71. if (Transport == NULL) {
  72. try_return (Status = STATUS_OBJECT_NAME_NOT_FOUND);
  73. }
  74. PagedTransport = Transport->PagedTransport;
  75. dlog(DPRT_FSCTL,
  76. ("%s: %ws: NtDeviceIoControlFile: GetMasterName\n",
  77. Transport->DomainInfo->DomOemDomainName,
  78. PagedTransport->TransportName.Buffer ));
  79. PagedTransport->ElectionCount = ELECTION_COUNT;
  80. Status = BowserQueueNonBufferRequest(Irp,
  81. &Transport->FindMasterQueue,
  82. BowserCancelQueuedRequest
  83. );
  84. if (!NT_SUCCESS(Status)) {
  85. try_return(Status);
  86. }
  87. Status = BowserFindMaster(Transport);
  88. //
  89. // If we couldn't initiate the find master process, complete all the
  90. // queued find master requests.
  91. //
  92. if (!NT_SUCCESS(Status)) {
  93. BowserCompleteFindMasterRequests(Transport, &PagedTransport->MasterName, Status);
  94. }
  95. //
  96. // Since we marked the IRP as pending, we need to return pending
  97. // now.
  98. //
  99. try_return(Status = STATUS_PENDING);
  100. try_exit:NOTHING;
  101. } finally {
  102. if ( Transport != NULL ) {
  103. BowserDereferenceTransport(Transport);
  104. }
  105. }
  106. return(Status);
  107. UNREFERENCED_PARAMETER(Wait);
  108. UNREFERENCED_PARAMETER(InFsd);
  109. }
  110. DATAGRAM_HANDLER(BowserHandleElection)
  111. {
  112. // PTA_NETBIOS_ADDRESS Address = SourceAddress;
  113. return BowserPostDatagramToWorkerThread(
  114. TransportName,
  115. Buffer,
  116. BytesAvailable,
  117. BytesTaken,
  118. SourceAddress,
  119. SourceAddressLength,
  120. SourceName,
  121. SourceNameLength,
  122. HandleElectionWorker,
  123. NonPagedPool,
  124. CriticalWorkQueue,
  125. ReceiveFlags,
  126. FALSE // Response will be sent, but...
  127. );
  128. }
  129. VOID
  130. HandleElectionWorker(
  131. IN PVOID Ctx
  132. )
  133. {
  134. PPOST_DATAGRAM_CONTEXT Context = Ctx;
  135. PTRANSPORT_NAME TransportName = Context->TransportName;
  136. PREQUEST_ELECTION_1 ElectionResponse = Context->Buffer;
  137. ULONG BytesAvailable = Context->BytesAvailable;
  138. ULONG TimeUp;
  139. BOOLEAN Winner;
  140. PTRANSPORT Transport = TransportName->Transport;
  141. NTSTATUS Status;
  142. LONG ElectionDelay, NextElection;
  143. OEM_STRING ClientNameO;
  144. UNICODE_STRING ClientName;
  145. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  146. PAGED_CODE();
  147. LOCK_TRANSPORT(Transport);
  148. ClientName.Buffer = NULL;
  149. try {
  150. //
  151. // If this packet was smaller than a minimal packet,
  152. // ignore the packet.
  153. //
  154. if (BytesAvailable <= FIELD_OFFSET(REQUEST_ELECTION_1, ServerName)) {
  155. try_return(NOTHING);
  156. }
  157. //
  158. // If the packet doesn't have a zero terminated ServerName,
  159. // ignore the packet.
  160. //
  161. if ( !IsZeroTerminated(
  162. ElectionResponse->ServerName,
  163. BytesAvailable - FIELD_OFFSET(REQUEST_ELECTION_1, ServerName) ) ) {
  164. try_return(NOTHING);
  165. }
  166. BowserStatistics.NumberOfElectionPackets += 1;
  167. //
  168. // Remember the last time we heard an election packet.
  169. //
  170. PagedTransport->LastElectionSeen = BowserTimeUp();
  171. if (Transport->ElectionState == DeafToElections) {
  172. try_return(NOTHING);
  173. }
  174. //
  175. // If we've disable the transport for any reason,
  176. // then we disregard all elections.
  177. //
  178. if (PagedTransport->DisabledTransport) {
  179. try_return(NOTHING);
  180. }
  181. //
  182. // Convert the client name in the election packet to unicode so we can
  183. // log it.
  184. //
  185. RtlInitString(&ClientNameO, ElectionResponse->ServerName);
  186. Status = RtlOemStringToUnicodeString(&ClientName, &ClientNameO, TRUE);
  187. if (!NT_SUCCESS(Status)) {
  188. BowserLogIllegalName( Status, ClientNameO.Buffer, ClientNameO.Length );
  189. try_return(NOTHING);
  190. }
  191. if (BowserLogElectionPackets) {
  192. BowserWriteErrorLogEntry(EVENT_BOWSER_ELECTION_RECEIVED, STATUS_SUCCESS, ElectionResponse, (USHORT)BytesAvailable, 2, ClientName.Buffer, PagedTransport->TransportName.Buffer);
  193. }
  194. dlog(DPRT_ELECT,
  195. ("%s: %ws: Received election packet from machine %s. Version: %lx; Criteria: %lx; TimeUp: %lx\n",
  196. Transport->DomainInfo->DomOemDomainName,
  197. PagedTransport->TransportName.Buffer,
  198. ElectionResponse->ServerName,
  199. ElectionResponse->Version,
  200. SmbGetUlong(&ElectionResponse->Criteria),
  201. SmbGetUlong(&ElectionResponse->TimeUp)));
  202. //
  203. // Figure out our time up for the election compare.
  204. //
  205. // If we're running an election, we'll use our advertised time, else
  206. // we'll use our actual uptime. Also, if we're running an election
  207. // we'll check to see if we sent this. If we're not running an election
  208. // and we receive this, it's because the redirector didn't find a
  209. // master, so we want to continue the election and become master.
  210. //
  211. if (Transport->ElectionState == RunningElection) {
  212. if (!strcmp(Transport->DomainInfo->DomOemComputerNameBuffer, ElectionResponse->ServerName)) {
  213. try_return(NOTHING);
  214. }
  215. //
  216. // If this request was initiated from a client, ignore it.
  217. //
  218. if ((SmbGetUlong(&ElectionResponse->Criteria) == 0) &&
  219. (ElectionResponse->ServerName[0] == '\0')) {
  220. dlog(DPRT_ELECT,
  221. ("%s: %ws: Dummy election request ignored during election.\n",
  222. Transport->DomainInfo->DomOemDomainName,
  223. PagedTransport->TransportName.Buffer ));
  224. try_return(NOTHING);
  225. }
  226. if (PagedTransport->Role == Master) {
  227. ElectionDelay = BowserRandom(MASTER_ELECTION_DELAY);
  228. } else {
  229. ElectionDelay = ELECTION_RESPONSE_MIN + BowserRandom(ELECTION_RESPONSE_MAX-ELECTION_RESPONSE_MIN);
  230. }
  231. } else {
  232. //
  233. // Starting a new election - set various election criteria
  234. // including Uptime.
  235. //
  236. ElectionDelay = BowserSetElectionCriteria(PagedTransport);
  237. }
  238. TimeUp = PagedTransport->Uptime;
  239. if (ElectionResponse->Version != BROWSER_ELECTION_VERSION) {
  240. Winner = (ElectionResponse->Version < BROWSER_ELECTION_VERSION);
  241. } else if (SmbGetUlong(&ElectionResponse->Criteria) != PagedTransport->ElectionCriteria) {
  242. Winner = (SmbGetUlong(&ElectionResponse->Criteria) < PagedTransport->ElectionCriteria);
  243. } else if (TimeUp != SmbGetUlong(&ElectionResponse->TimeUp)) {
  244. Winner = TimeUp > SmbGetUlong(&ElectionResponse->TimeUp);
  245. } else {
  246. Winner = (strcmp(Transport->DomainInfo->DomOemDomainName, ElectionResponse->ServerName) <= 0);
  247. }
  248. //
  249. // If we lost, we stop our timer and turn off our election flag, just
  250. // in case we had an election or find master going. If we're a backup,
  251. // we want to find out who the new master is, either from this election
  252. // frame or waiting awhile and querying.
  253. //
  254. if (!Winner) {
  255. //
  256. // Remember if we legitimately lost the last election, and if
  257. // so, don't force an election if we see server announcements
  258. // from a non DC, just give up.
  259. //
  260. PagedTransport->Flags |= ELECT_LOST_LAST_ELECTION;
  261. }
  262. if (!Winner || (PagedTransport->ElectionsSent > ELECTION_MAX)) {
  263. if (PagedTransport->IsPrimaryDomainController) {
  264. DWORD ElectionInformation[6];
  265. ElectionInformation[0] = ElectionResponse->Version;
  266. ElectionInformation[1] = SmbGetUlong(&ElectionResponse->Criteria);
  267. ElectionInformation[2] = SmbGetUlong(&ElectionResponse->TimeUp);
  268. ElectionInformation[3] = BROWSER_ELECTION_VERSION;
  269. ElectionInformation[4] = PagedTransport->ElectionCriteria;
  270. ElectionInformation[5] = TimeUp;
  271. //
  272. // Write this information into the event log.
  273. //
  274. BowserWriteErrorLogEntry(EVENT_BOWSER_PDC_LOST_ELECTION,
  275. STATUS_SUCCESS,
  276. ElectionInformation,
  277. sizeof(ElectionInformation),
  278. 2,
  279. ClientName.Buffer,
  280. PagedTransport->TransportName.Buffer);
  281. KdPrint(("HandleElectionWorker: Lose election, but we're the PDC. Winner: Version: %lx; Criteria: %lx; Time Up: %lx; Name: %s\n",
  282. ElectionResponse->Version,
  283. SmbGetUlong(&ElectionResponse->Criteria),
  284. SmbGetUlong(&ElectionResponse->TimeUp),
  285. ElectionResponse->ServerName));
  286. }
  287. BowserLoseElection(Transport);
  288. } else {
  289. //
  290. // We won this election, make sure that we don't think that we
  291. // lost it.
  292. //
  293. PagedTransport->Flags &= ~ELECT_LOST_LAST_ELECTION;
  294. //
  295. // If we won and we're not running an election, we'll start one.
  296. // If we are running, we don't do anything because our timer will
  297. // take care of it. If the NET_ELECTION flag is clear, we know
  298. // timeup is approx. equal to time_up() because we set it above,
  299. // so we'll use that. This algorithm includes a damping constant
  300. // (we won't start an election if we've just lost one in the
  301. // last 1.5 seconds) to avoid election storms.
  302. //
  303. if (Transport->ElectionState != RunningElection) {
  304. //
  305. // If we recently lost an election, then ignore the fact
  306. // that we won, and pretend we lost this one.
  307. //
  308. if ((PagedTransport->TimeLastLost != 0) &&
  309. ((BowserTimeUp() - PagedTransport->TimeLastLost) < ELECTION_EXEMPT_TIME)) {
  310. dlog(DPRT_ELECT,
  311. ("%s: %ws: Browser is exempt from election\n",
  312. Transport->DomainInfo->DomOemDomainName,
  313. PagedTransport->TransportName.Buffer ));
  314. try_return(NOTHING);
  315. }
  316. dlog(DPRT_ELECT,
  317. ("%s: %ws: Better criteria, calling elect_master in %ld milliseconds.\n",
  318. Transport->DomainInfo->DomOemDomainName,
  319. PagedTransport->TransportName.Buffer,
  320. ElectionDelay));
  321. //
  322. // Ensure the timer is running.
  323. // We don't actually win the election until the timer expires.
  324. //
  325. Transport->ElectionState = RunningElection;
  326. PagedTransport->NextElection = 0;
  327. }
  328. PagedTransport->ElectionCount = ELECTION_COUNT;
  329. //
  330. // Note: the next elect time must be computed into a signed
  331. // integer in case the expiration time has already passed so
  332. // don't try to optimize this code too much.
  333. //
  334. NextElection = PagedTransport->NextElection - (TimeUp - BowserTimeUp());
  335. if ((PagedTransport->NextElection == 0) || NextElection > ElectionDelay) {
  336. BowserStopTimer(&Transport->ElectionTimer);
  337. PagedTransport->NextElection = TimeUp + ElectionDelay;
  338. dlog(DPRT_ELECT,
  339. ("%s: %ws: Calling ElectMaster in %ld milliseconds\n",
  340. Transport->DomainInfo->DomOemDomainName,
  341. PagedTransport->TransportName.Buffer,
  342. ElectionDelay));
  343. BowserStartTimer(&Transport->ElectionTimer, ElectionDelay, BowserElectMaster, Transport);
  344. }
  345. }
  346. try_exit:NOTHING;
  347. } finally {
  348. UNLOCK_TRANSPORT(Transport);
  349. InterlockedDecrement( &BowserPostedCriticalDatagramCount );
  350. FREE_POOL(Context);
  351. if (ClientName.Buffer != NULL) {
  352. RtlFreeUnicodeString(&ClientName);
  353. }
  354. BowserDereferenceTransportName(TransportName);
  355. BowserDereferenceTransport(Transport);
  356. }
  357. return;
  358. }
  359. LONG
  360. BowserSetElectionCriteria(
  361. IN PPAGED_TRANSPORT PagedTransport
  362. )
  363. /*++
  364. Routine Description:
  365. Set election criteria for a network.
  366. Prepare for an election by setting Transport->ElectionCriteria based upon the local
  367. browser state. Set Transport->Uptime to the current local up time.
  368. Arguments:
  369. Transport - The transport for the net we're on.
  370. Return Value
  371. Number of milliseconds to delay before sending the election packet.
  372. --*/
  373. {
  374. LONG Delay;
  375. PAGED_CODE();
  376. PagedTransport->ElectionsSent = 0; // clear bid counter
  377. PagedTransport->Uptime = BowserTimeUp();
  378. if (BowserData.IsLanmanNt) {
  379. PagedTransport->ElectionCriteria = ELECTION_CR_LM_NT;
  380. } else {
  381. PagedTransport->ElectionCriteria = ELECTION_CR_WIN_NT;
  382. }
  383. PagedTransport->ElectionCriteria |=
  384. ELECTION_MAKE_REV(BROWSER_VERSION_MAJOR, BROWSER_VERSION_MINOR);
  385. if (BowserData.MaintainServerList &&
  386. ((PagedTransport->NumberOfServersInTable +
  387. RtlNumberGenericTableElements(&PagedTransport->AnnouncementTable)+
  388. RtlNumberGenericTableElements(&PagedTransport->DomainTable)) != 0)) {
  389. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_CFG_BKP;
  390. }
  391. if (PagedTransport->IsPrimaryDomainController) {
  392. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_PDC;
  393. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_DOMMSTR;
  394. }
  395. #ifdef ENABLE_PSEUDO_BROWSER
  396. if (BowserData.PseudoServerLevel == BROWSER_PSEUDO ||
  397. BowserData.PseudoServerLevel == BROWSER_SEMI_PSEUDO_NO_DMB ) {
  398. // Pseudo or Semi-Pseudo will win elections over peers
  399. // & in case of semi-pseudo except no DMB communications
  400. // all other functionality will remain on.
  401. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_PSEUDO;
  402. }
  403. #endif
  404. if (PagedTransport->Role == Master) {
  405. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_MASTER;
  406. Delay = MASTER_ELECTION_DELAY;
  407. } else if (PagedTransport->IsPrimaryDomainController) {
  408. //
  409. // If we are the PDC, we want to set our timeouts
  410. // as if we were already the master.
  411. //
  412. // This prevents us from getting into a situation where it takes
  413. // more than ELECTION_DELAY_MAX to actually send out our response
  414. // to an election.
  415. //
  416. Delay = MASTER_ELECTION_DELAY;
  417. } else if ((PagedTransport->Role == Backup) ||
  418. BowserData.IsLanmanNt) {
  419. //
  420. // Likewise, if we are NTAS machines, we want to set out delay
  421. // to match that of backup browsers (even if we're not a backup
  422. // quite yet).
  423. //
  424. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_BACKUP;
  425. Delay = BACKUP_ELECTION_DELAY_MIN + BowserRandom(BACKUP_ELECTION_DELAY_MAX-BACKUP_ELECTION_DELAY_MIN);
  426. } else {
  427. Delay = ELECTION_DELAY_MIN + BowserRandom(ELECTION_DELAY_MAX-ELECTION_DELAY_MIN);
  428. }
  429. //
  430. // Assume for now that all wannish transports are running the WINS client.
  431. //
  432. if ( PagedTransport->Wannish ) {
  433. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_WINS_CLIENT;
  434. }
  435. return Delay;
  436. }
  437. NTSTATUS
  438. BowserStartElection(
  439. IN PTRANSPORT Transport
  440. )
  441. /*++
  442. Routine Description:
  443. Initiate a browser election
  444. This routine is called when we are unable to find a master, and we want to
  445. elect one.
  446. Arguments:
  447. Transport - The transport for the net we're on.
  448. Return Value
  449. None.
  450. --*/
  451. {
  452. NTSTATUS Status = STATUS_SUCCESS;
  453. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  454. PAGED_CODE();
  455. LOCK_TRANSPORT(Transport);
  456. try {
  457. //
  458. // If we've disable the transport for any reason,
  459. // then we disregard all elections.
  460. //
  461. if (PagedTransport->DisabledTransport) {
  462. try_return(Status = STATUS_UNSUCCESSFUL);
  463. }
  464. //
  465. // If we're deaf to elections, or aren't any kind of
  466. // browser then we can't start elections either.
  467. //
  468. if (Transport->ElectionState == DeafToElections ||
  469. PagedTransport->Role == None) {
  470. try_return(Status = STATUS_UNSUCCESSFUL);
  471. }
  472. PagedTransport->ElectionCount = ELECTION_COUNT;
  473. Transport->ElectionState = RunningElection;
  474. BowserSetElectionCriteria(PagedTransport);
  475. Status = BowserElectMaster(Transport);
  476. try_exit:NOTHING;
  477. } finally {
  478. UNLOCK_TRANSPORT(Transport);
  479. }
  480. return Status;
  481. }
  482. NTSTATUS
  483. BowserElectMaster(
  484. IN PTRANSPORT Transport
  485. )
  486. /*++
  487. Routine Description:
  488. Elect a master browser server.
  489. This routine is called when we think there is no master and we need to
  490. elect one. We check our retry count, and if it's non-zero we send an
  491. elect datagram to the group name. Otherwise we become the master ourselves.
  492. Arguments:
  493. Transport - The transport for the net we're on.
  494. Return Value
  495. None.
  496. --*/
  497. {
  498. NTSTATUS Status;
  499. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  500. PAGED_CODE();
  501. LOCK_TRANSPORT(Transport);
  502. try {
  503. //
  504. // If we're not running the election at this time, it means that
  505. // between the time that we decided we were going to win the election
  506. // and now, someone else announced with better criteria. It is
  507. // possible that this could happen if the announcement came in just
  508. // before we ran (ie. if the announcement occured between when the
  509. // timer DPC was queued and when the DPC actually fired).
  510. //
  511. if (Transport->ElectionState != RunningElection) {
  512. KdPrint(("BowserElectMaster: Lose election because we are no longer running the election\n"));
  513. BowserLoseElection(Transport);
  514. } else if (PagedTransport->ElectionCount != 0) {
  515. BowserStopTimer(&Transport->ElectionTimer);
  516. PagedTransport->ElectionCount -= 1;
  517. PagedTransport->ElectionsSent += 1;
  518. PagedTransport->NextElection = BowserTimeUp() + ELECTION_RESEND_DELAY;
  519. Status = BowserSendElection(&Transport->DomainInfo->DomUnicodeDomainName, BrowserElection, Transport, TRUE);
  520. // Lose the election if we can't send a datagram.
  521. if (!NT_SUCCESS(Status)) {
  522. BowserLoseElection(Transport);
  523. try_return(Status);
  524. }
  525. //
  526. // If we were able to send the election,
  527. // start the timer running.
  528. //
  529. BowserStartTimer(&Transport->ElectionTimer,
  530. ELECTION_RESEND_DELAY,
  531. BowserElectMaster,
  532. Transport);
  533. } else {
  534. Transport->ElectionState = Idle;
  535. //
  536. // If we're already the master we just return. This can happen if
  537. // somebody starts an election (which we win) while we're already
  538. // the master.
  539. //
  540. if (PagedTransport->Role != Master) {
  541. //
  542. // We're the new master - we won!
  543. //
  544. BowserNewMaster(Transport, Transport->DomainInfo->DomOemComputerNameBuffer );
  545. } else {
  546. //
  547. // Were already the master. Make sure that all the backups
  548. // know this by sending an announcent
  549. //
  550. //
  551. // This one's easy - simply set the servers announcement event to the
  552. // signalled state. If the server is running, this will force an
  553. // announcement
  554. //
  555. KeSetEvent(BowserServerAnnouncementEvent, IO_NETWORK_INCREMENT, FALSE);
  556. }
  557. }
  558. try_return(Status = STATUS_SUCCESS);
  559. try_exit:NOTHING;
  560. } finally {
  561. UNLOCK_TRANSPORT(Transport);
  562. }
  563. return Status;
  564. }
  565. VOID
  566. BowserLoseElection(
  567. IN PTRANSPORT Transport
  568. )
  569. {
  570. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  571. PAGED_CODE();
  572. LOCK_TRANSPORT(Transport);
  573. BowserStopTimer(&Transport->ElectionTimer);
  574. dlog(DPRT_ELECT,
  575. ("We lost the election\n",
  576. Transport->DomainInfo->DomOemDomainName,
  577. PagedTransport->TransportName.Buffer ));
  578. PagedTransport->TimeLastLost = BowserTimeUp();
  579. //
  580. // We lost the election - we re-enter the idle state.
  581. //
  582. Transport->ElectionState = Idle;
  583. if (PagedTransport->Role == Master) {
  584. //
  585. // If we lost, and we are currently a master, then tickle
  586. // the browser service and stop being a master.
  587. //
  588. BowserResetStateForTransport(Transport, RESET_STATE_STOP_MASTER);
  589. //
  590. // Remove all the entries on the server list for this
  591. // transport.
  592. //
  593. LOCK_ANNOUNCE_DATABASE(Transport);
  594. //
  595. // Flag that there should be no more announcements received on
  596. // this name.
  597. //
  598. BowserForEachTransportName(Transport, BowserStopProcessingAnnouncements, NULL);
  599. // KdPrint(("Deleting entire table on transport %wZ because we lost the election\n", &Transport->TransportName));
  600. BowserDeleteGenericTable(&PagedTransport->AnnouncementTable);
  601. BowserDeleteGenericTable(&PagedTransport->DomainTable);
  602. UNLOCK_ANNOUNCE_DATABASE(Transport);
  603. #if 0
  604. } else if (Transport->Role == Backup) { // If we're a backup, find master
  605. dlog(DPRT_ELECT, ("We're a backup - Find the new master\n"));
  606. //
  607. // If this guy is not the master, then we want to
  608. // find a master at some later time.
  609. //
  610. Transport->ElectionCount = FIND_MASTER_COUNT;
  611. Transport->Uptime = Transport->TimeLastLost;
  612. BowserStopTimer(&Transport->FindMasterTimer);
  613. BowserStartTimer(&Transport->FindMasterTimer,
  614. FIND_MASTER_WAIT-(FIND_MASTER_WAIT/8)+ BowserRandom(FIND_MASTER_WAIT/4),
  615. BowserFindMaster,
  616. Transport);
  617. #endif
  618. }
  619. UNLOCK_TRANSPORT(Transport);
  620. }
  621. NTSTATUS
  622. BowserFindMaster(
  623. IN PTRANSPORT Transport
  624. )
  625. /*++
  626. Routine Description:
  627. Find the master browser server.
  628. This routine attempts to find the master browser server by
  629. sending a request announcement message to the master. If no response is
  630. heard after a while, we assume the master isn't present and run and
  631. election.
  632. Arguments:
  633. Transport - The transport for the net we're on.
  634. Return Value
  635. None.
  636. --*/
  637. {
  638. NTSTATUS Status;
  639. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  640. PAGED_CODE();
  641. LOCK_TRANSPORT(Transport);
  642. try {
  643. //
  644. // If our count hasn't gone to 0 yet, we'll send a find master PDU.
  645. //
  646. if (PagedTransport->ElectionCount != 0) {
  647. PagedTransport->ElectionCount -= 1; // Update count, and set timer
  648. BowserStopTimer(&Transport->FindMasterTimer);
  649. Status = BowserSendRequestAnnouncement(
  650. &Transport->DomainInfo->DomUnicodeDomainName,
  651. MasterBrowser,
  652. Transport);
  653. if (NT_SUCCESS(Status) ||
  654. Status == STATUS_BAD_NETWORK_PATH) {
  655. //
  656. // We will retry on the following cases:
  657. // - netbt returns success. Meaning I'll be looking for it.
  658. // - nwlnknb returns STATUS_BAD_NETWORK_PATH meaning I can't find it.
  659. // In either case, we would try for ElectionCount times & then move
  660. // fwd to initiate elections. Otherwise we may end up in a state where because
  661. // we didn't find a master browser, we won't attempt to elect one & we'll fail
  662. // to become one. This will result w/ a domain w/ no master browser.
  663. //
  664. BowserStartTimer(&Transport->FindMasterTimer,
  665. FIND_MASTER_DELAY,
  666. BowserFindMaster,
  667. Transport);
  668. } else {
  669. try_return(Status);
  670. }
  671. } else {
  672. ULONG CurrentTime;
  673. LONG TimeTilNextElection;
  674. //
  675. // Count has expired, so we'll try to elect a new master.
  676. //
  677. dlog(DPRT_ELECT,
  678. ("%s: %ws: Find_Master: Master not found, forcing election.\n",
  679. Transport->DomainInfo->DomOemDomainName,
  680. PagedTransport->TransportName.Buffer ));
  681. if (BowserLogElectionPackets) {
  682. BowserWriteErrorLogEntry(EVENT_BOWSER_ELECTION_SENT_FIND_MASTER_FAILED, STATUS_SUCCESS, NULL, 0, 1, PagedTransport->TransportName.Buffer);
  683. }
  684. //
  685. // If it's been more than a reasonable of time since the last
  686. // election, force a new election, otherwise set a timer to
  687. // start an election after a reasonable amount of time.
  688. //
  689. //
  690. // Calculate the time until the next election only once
  691. // since it is possible that we might cross over the ELECTION_TIME
  692. // threshold while performing these checks.
  693. //
  694. CurrentTime = BowserTimeUp();
  695. if ( CurrentTime >= PagedTransport->LastElectionSeen) {
  696. TimeTilNextElection = (ELECTION_TIME - (CurrentTime - PagedTransport->LastElectionSeen));
  697. } else {
  698. TimeTilNextElection = ELECTION_TIME;
  699. }
  700. if ( TimeTilNextElection <= 0 ) {
  701. dlog(DPRT_ELECT,
  702. ("%s: %ws: Last election long enough ago, forcing election\n",
  703. Transport->DomainInfo->DomOemDomainName,
  704. PagedTransport->TransportName.Buffer ));
  705. Status = BowserStartElection(Transport);
  706. //
  707. // If we couldn't start the election, complete the find
  708. // master requests with the appropriate error.
  709. //
  710. if (!NT_SUCCESS(Status)) {
  711. //
  712. // Complete the requests with the current master name - it's
  713. // as good as anyone.
  714. //
  715. BowserCompleteFindMasterRequests(Transport, &PagedTransport->MasterName, Status);
  716. }
  717. } else {
  718. dlog(DPRT_ELECT,
  719. ("%s: %ws: Last election too recent, delay %ld before forcing election\n",
  720. Transport->DomainInfo->DomOemDomainName,
  721. PagedTransport->TransportName.Buffer,
  722. TimeTilNextElection ));
  723. BowserStartTimer(&Transport->FindMasterTimer,
  724. TimeTilNextElection,
  725. BowserStartElection,
  726. Transport);
  727. }
  728. }
  729. try_return(Status = STATUS_SUCCESS);
  730. try_exit:NOTHING;
  731. } finally {
  732. UNLOCK_TRANSPORT(Transport);
  733. }
  734. return Status;
  735. }
  736. NTSTATUS
  737. BowserSendElection(
  738. IN PUNICODE_STRING NameToSend OPTIONAL,
  739. IN DGRECEIVER_NAME_TYPE NameType,
  740. IN PTRANSPORT Transport,
  741. IN BOOLEAN SendActualBrowserInfo
  742. )
  743. {
  744. UCHAR Buffer[sizeof(REQUEST_ELECTION)+LM20_CNLEN+1];
  745. PREQUEST_ELECTION ElectionRequest = (PREQUEST_ELECTION) Buffer;
  746. ULONG ComputerNameSize;
  747. NTSTATUS Status;
  748. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  749. PAGED_CODE();
  750. ElectionRequest->Type = Election;
  751. //
  752. // If this transport is disabled,
  753. // don't send any election packets.
  754. //
  755. if ( PagedTransport->DisabledTransport ) {
  756. return STATUS_UNSUCCESSFUL;
  757. }
  758. //
  759. // If we are supposed to send the actual browser info, and we are
  760. // running the browser send a real election packet, otherwise we
  761. // just want to send a dummy packet.
  762. //
  763. if (SendActualBrowserInfo &&
  764. (PagedTransport->ServiceStatus & (SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_BACKUP_BROWSER | SV_TYPE_MASTER_BROWSER))) {
  765. dlog(DPRT_ELECT,
  766. ("%s: %ws: Send true election.\n",
  767. Transport->DomainInfo->DomOemDomainName,
  768. PagedTransport->TransportName.Buffer ));
  769. //
  770. // If this request comes as a part of an election, we want to send
  771. // the accurate browser information.
  772. //
  773. ElectionRequest->ElectionRequest.Version = BROWSER_ELECTION_VERSION;
  774. ElectionRequest->ElectionRequest.TimeUp = PagedTransport->Uptime;
  775. ElectionRequest->ElectionRequest.Criteria = PagedTransport->ElectionCriteria;
  776. ElectionRequest->ElectionRequest.MustBeZero = 0;
  777. ComputerNameSize = Transport->DomainInfo->DomOemComputerName.Length;
  778. strcpy( ElectionRequest->ElectionRequest.ServerName,
  779. Transport->DomainInfo->DomOemComputerName.Buffer );
  780. } else {
  781. dlog(DPRT_ELECT,
  782. ("%s: %ws: Send dummy election.\n",
  783. Transport->DomainInfo->DomOemDomainName,
  784. PagedTransport->TransportName.Buffer ));
  785. //
  786. // If we are forcing the election because we can't get a backup list,
  787. // send only dummy information.
  788. //
  789. ElectionRequest->ElectionRequest.Version = 0;
  790. ElectionRequest->ElectionRequest.Criteria = 0;
  791. ElectionRequest->ElectionRequest.TimeUp = 0;
  792. ElectionRequest->ElectionRequest.ServerName[0] = '\0';
  793. ElectionRequest->ElectionRequest.MustBeZero = 0;
  794. ComputerNameSize = 0;
  795. }
  796. return BowserSendSecondClassMailslot(Transport,
  797. NameToSend,
  798. NameType,
  799. ElectionRequest,
  800. FIELD_OFFSET(REQUEST_ELECTION, ElectionRequest.ServerName)+ComputerNameSize+sizeof(UCHAR),
  801. TRUE,
  802. MAILSLOT_BROWSER_NAME,
  803. NULL
  804. );
  805. }