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.

1738 lines
53 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. brdevice.c
  5. Abstract:
  6. This module contains the support routines for the APIs that call
  7. into the browser or the datagram receiver.
  8. Author:
  9. Rita Wong (ritaw) 20-Feb-1991
  10. Larry Osterman (larryo) 23-Mar-1992
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //-------------------------------------------------------------------//
  16. // //
  17. // Local Function Prototypes //
  18. // //
  19. //-------------------------------------------------------------------//
  20. //-------------------------------------------------------------------//
  21. // //
  22. // Global variables //
  23. // //
  24. //-------------------------------------------------------------------//
  25. // Event for synchronization of asynchronous I/O completion against the
  26. // datagram receiver
  27. HANDLE BrDgAsyncIOShutDownEvent;
  28. HANDLE BrDgAsyncIOThreadShutDownEvent;
  29. BOOL BrDgShutDownInitiated = FALSE;
  30. DWORD BrDgAsyncIOsOutstanding = 0;
  31. DWORD BrDgWorkerThreadsOutstanding = 0;
  32. CRITICAL_SECTION BrAsyncIOCriticalSection;
  33. //
  34. // Handle to the Datagram Receiver DD
  35. //
  36. HANDLE BrDgReceiverDeviceHandle = NULL;
  37. VOID
  38. CompleteAsyncBrowserIoControl(
  39. IN PVOID ApcContext,
  40. IN PIO_STATUS_BLOCK IoStatusBlock,
  41. IN ULONG Reserved
  42. );
  43. VOID
  44. BrDecrementOutstandingIos()
  45. /*++
  46. Routine Description:
  47. Decrements the outstanding IO count, and signals the event if necessary
  48. Arguments:
  49. None.
  50. Return Value:
  51. VOID
  52. --*/
  53. {
  54. BOOL SignalAsyncIOShutDownEvent = FALSE;
  55. EnterCriticalSection(&BrAsyncIOCriticalSection);
  56. BrDgAsyncIOsOutstanding -= 1;
  57. if (BrDgAsyncIOsOutstanding == 0 &&
  58. BrDgShutDownInitiated) {
  59. SignalAsyncIOShutDownEvent = TRUE;
  60. }
  61. LeaveCriticalSection(&BrAsyncIOCriticalSection);
  62. if (SignalAsyncIOShutDownEvent) {
  63. SetEvent(BrDgAsyncIOShutDownEvent);
  64. }
  65. }
  66. NET_API_STATUS
  67. BrOpenDgReceiver (
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. This routine opens the NT LAN Man Datagram Receiver driver.
  73. Arguments:
  74. None.
  75. Return Value:
  76. NET_API_STATUS - NERR_Success or reason for failure.
  77. --*/
  78. {
  79. NET_API_STATUS Status;
  80. NTSTATUS ntstatus;
  81. UNICODE_STRING DeviceName;
  82. IO_STATUS_BLOCK IoStatusBlock;
  83. OBJECT_ATTRIBUTES ObjectAttributes;
  84. //
  85. // Open the redirector device.
  86. //
  87. RtlInitUnicodeString(&DeviceName, DD_BROWSER_DEVICE_NAME_U);
  88. InitializeObjectAttributes(
  89. &ObjectAttributes,
  90. &DeviceName,
  91. OBJ_CASE_INSENSITIVE,
  92. NULL,
  93. NULL
  94. );
  95. ntstatus = NtOpenFile(
  96. &BrDgReceiverDeviceHandle,
  97. SYNCHRONIZE,
  98. &ObjectAttributes,
  99. &IoStatusBlock,
  100. 0,
  101. 0
  102. );
  103. if (NT_SUCCESS(ntstatus)) {
  104. ntstatus = IoStatusBlock.Status;
  105. }
  106. if (! NT_SUCCESS(ntstatus)) {
  107. BrPrint(( BR_CRITICAL,"NtOpenFile browser driver failed: 0x%08lx\n",
  108. ntstatus));
  109. }
  110. Status = NetpNtStatusToApiStatus(ntstatus);
  111. if (NT_SUCCESS(ntstatus)) {
  112. // Initialize the event and the critical section used for async I/O
  113. try {
  114. BrDgShutDownInitiated = FALSE;
  115. BrDgAsyncIOsOutstanding = 0;
  116. BrDgWorkerThreadsOutstanding = 0;
  117. InitializeCriticalSection( &BrAsyncIOCriticalSection );
  118. BrDgAsyncIOShutDownEvent =
  119. CreateEvent(
  120. NULL, // Event attributes
  121. TRUE, // Event must be manually reset
  122. FALSE,
  123. NULL // Initial state not signalled
  124. );
  125. if (BrDgAsyncIOShutDownEvent == NULL) {
  126. DeleteCriticalSection(&BrAsyncIOCriticalSection);
  127. Status = GetLastError();
  128. }
  129. BrDgAsyncIOThreadShutDownEvent =
  130. CreateEvent(
  131. NULL,
  132. TRUE,
  133. FALSE,
  134. NULL
  135. );
  136. if( BrDgAsyncIOThreadShutDownEvent == NULL ) {
  137. CloseHandle( BrDgAsyncIOShutDownEvent );
  138. BrDgAsyncIOShutDownEvent = NULL;
  139. DeleteCriticalSection(&BrAsyncIOCriticalSection);
  140. Status = GetLastError();
  141. }
  142. }
  143. except ( EXCEPTION_EXECUTE_HANDLER ) {
  144. Status = ERROR_NO_SYSTEM_RESOURCES;
  145. }
  146. }
  147. return Status;
  148. }
  149. VOID
  150. BrShutdownDgReceiver(
  151. VOID
  152. )
  153. /*++
  154. Routine Description:
  155. This routine close the LAN Man Redirector device.
  156. Arguments:
  157. None.
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. IO_STATUS_BLOCK IoSb;
  163. LARGE_INTEGER timeout;
  164. BOOL WaitForAsyncIOCompletion = FALSE;
  165. DWORD waitResult = 0;
  166. EnterCriticalSection(&BrAsyncIOCriticalSection);
  167. BrDgShutDownInitiated = TRUE;
  168. if (BrDgAsyncIOsOutstanding != 0) {
  169. WaitForAsyncIOCompletion = TRUE;
  170. }
  171. LeaveCriticalSection(&BrAsyncIOCriticalSection);
  172. if (WaitForAsyncIOCompletion) {
  173. //
  174. // Cancel the I/O operations outstanding on the browser.
  175. // Then wait for the shutdown event to be signalled, but allow
  176. // APC's to be called to call our completion routine.
  177. //
  178. NtCancelIoFile(BrDgReceiverDeviceHandle, &IoSb);
  179. do {
  180. waitResult = WaitForSingleObjectEx(BrDgAsyncIOShutDownEvent,0xffffffff, TRUE);
  181. }
  182. while( waitResult == WAIT_IO_COMPLETION );
  183. }
  184. ASSERT(BrDgAsyncIOsOutstanding == 0);
  185. EnterCriticalSection(&BrAsyncIOCriticalSection);
  186. // Wait for the final worker thread to exit if necessary
  187. if( BrDgWorkerThreadsOutstanding > 0 )
  188. {
  189. WaitForAsyncIOCompletion = TRUE;
  190. }
  191. else
  192. {
  193. WaitForAsyncIOCompletion = FALSE;
  194. }
  195. LeaveCriticalSection(&BrAsyncIOCriticalSection);
  196. if( WaitForAsyncIOCompletion )
  197. {
  198. // This will either be signalled from before, or the final worker thread will signal it.
  199. WaitForSingleObject( BrDgAsyncIOThreadShutDownEvent, 0xffffffff );
  200. }
  201. if (BrDgAsyncIOShutDownEvent != NULL) {
  202. CloseHandle(BrDgAsyncIOShutDownEvent);
  203. CloseHandle(BrDgAsyncIOThreadShutDownEvent);
  204. DeleteCriticalSection(&BrAsyncIOCriticalSection);
  205. }
  206. }
  207. //
  208. // Retreive the list of bound transports from the bowser driver.
  209. //
  210. NET_API_STATUS
  211. BrGetTransportList(
  212. OUT PLMDR_TRANSPORT_LIST *TransportList
  213. )
  214. {
  215. NET_API_STATUS Status;
  216. LMDR_REQUEST_PACKET RequestPacket;
  217. //
  218. // If we have a previous buffer that was too small, free it up.
  219. //
  220. RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  221. RequestPacket.Type = EnumerateXports;
  222. RtlInitUnicodeString(&RequestPacket.TransportName, NULL);
  223. RtlInitUnicodeString(&RequestPacket.EmulatedDomainName, NULL);
  224. Status = DeviceControlGetInfo(
  225. BrDgReceiverDeviceHandle,
  226. IOCTL_LMDR_ENUMERATE_TRANSPORTS,
  227. &RequestPacket,
  228. sizeof(RequestPacket),
  229. (LPVOID *)TransportList,
  230. 0xffffffff,
  231. 4096,
  232. NULL
  233. );
  234. return Status;
  235. }
  236. NET_API_STATUS
  237. BrAnnounceDomain(
  238. IN PNETWORK Network,
  239. IN ULONG Periodicity
  240. )
  241. {
  242. NET_API_STATUS Status;
  243. UCHAR AnnounceBuffer[sizeof(BROWSE_ANNOUNCE_PACKET)+LM20_CNLEN+1];
  244. PBROWSE_ANNOUNCE_PACKET Announcement = (PBROWSE_ANNOUNCE_PACKET )AnnounceBuffer;
  245. //
  246. // We don't announce domains on direct host IPX.
  247. //
  248. if (Network->Flags & NETWORK_IPX) {
  249. return NERR_Success;
  250. }
  251. Announcement->BrowseType = WkGroupAnnouncement;
  252. Announcement->BrowseAnnouncement.Periodicity = Periodicity;
  253. Announcement->BrowseAnnouncement.UpdateCount = 0;
  254. Announcement->BrowseAnnouncement.VersionMajor = BROWSER_CONFIG_VERSION_MAJOR;
  255. Announcement->BrowseAnnouncement.VersionMinor = BROWSER_CONFIG_VERSION_MINOR;
  256. Announcement->BrowseAnnouncement.Type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_NT;
  257. if (Network->Flags & NETWORK_PDC ) {
  258. Announcement->BrowseAnnouncement.Type |= SV_TYPE_DOMAIN_CTRL;
  259. }
  260. lstrcpyA(Announcement->BrowseAnnouncement.ServerName, Network->DomainInfo->DomOemDomainName);
  261. lstrcpyA(Announcement->BrowseAnnouncement.Comment, Network->DomainInfo->DomOemComputerName );
  262. Status = SendDatagram(BrDgReceiverDeviceHandle,
  263. &Network->NetworkName,
  264. &Network->DomainInfo->DomUnicodeDomainNameString,
  265. Network->DomainInfo->DomUnicodeDomainName,
  266. DomainAnnouncement,
  267. Announcement,
  268. FIELD_OFFSET(BROWSE_ANNOUNCE_PACKET, BrowseAnnouncement.Comment)+
  269. Network->DomainInfo->DomOemComputerNameLength+sizeof(UCHAR)
  270. );
  271. if (Status != NERR_Success) {
  272. BrPrint(( BR_CRITICAL,
  273. "%ws: Unable to announce domain for network %wZ: %X\n",
  274. Network->DomainInfo->DomUnicodeDomainName,
  275. &Network->NetworkName,
  276. Status));
  277. }
  278. return Status;
  279. }
  280. NET_API_STATUS
  281. BrUpdateBrowserStatus (
  282. IN PNETWORK Network,
  283. IN DWORD ServiceStatus
  284. )
  285. {
  286. NET_API_STATUS Status;
  287. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
  288. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  289. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  290. RequestPacket->TransportName = Network->NetworkName;
  291. RequestPacket->EmulatedDomainName = Network->DomainInfo->DomUnicodeDomainNameString;
  292. RequestPacket->Parameters.UpdateStatus.NewStatus = ServiceStatus;
  293. RequestPacket->Parameters.UpdateStatus.IsLanmanNt = (BrInfo.IsLanmanNt != FALSE);
  294. #ifdef ENABLE_PSEUDO_BROWSER
  295. RequestPacket->Parameters.UpdateStatus.PseudoServerLevel = (BOOL)(BrInfo.PseudoServerLevel);
  296. #endif
  297. // RequestPacket->Parameters.UpdateStatus.IsMemberDomain = TRUE; // Not used
  298. // RequestPacket->Parameters.UpdateStatus.IsPrimaryDomainController = Network->DomainInfo->IsPrimaryDomainController;
  299. // RequestPacket->Parameters.UpdateStatus.IsDomainMaster = Network->DomainInfo->IsDomainMasterBrowser;
  300. RequestPacket->Parameters.UpdateStatus.MaintainServerList = (BrInfo.MaintainServerList == 1);
  301. //
  302. // Tell the bowser the number of servers in the server table.
  303. //
  304. RequestPacket->Parameters.UpdateStatus.NumberOfServersInTable =
  305. NumberInterimServerListElements(&Network->BrowseTable) +
  306. NumberInterimServerListElements(&Network->DomainList) +
  307. Network->TotalBackupServerListEntries +
  308. Network->TotalBackupDomainListEntries;
  309. //
  310. // This is a simple IoControl - It just updates the status.
  311. //
  312. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  313. IOCTL_LMDR_UPDATE_STATUS,
  314. RequestPacket,
  315. sizeof(LMDR_REQUEST_PACKET),
  316. NULL,
  317. 0,
  318. NULL);
  319. return Status;
  320. }
  321. NET_API_STATUS
  322. BrIssueAsyncBrowserIoControl(
  323. IN PNETWORK Network OPTIONAL,
  324. IN ULONG ControlCode,
  325. IN PBROWSER_WORKER_ROUTINE CompletionRoutine,
  326. IN PVOID OptionalParameter
  327. )
  328. /*++
  329. Routine Description:
  330. Issue an asynchronous Io Control to the browser. Call the specified
  331. completion routine when the IO finishes.
  332. Arguments:
  333. Network - Network the function applies to
  334. If this parameter is not supplied, the operation is not related to a
  335. particular network..
  336. ControlCode - IoControl function code
  337. CompletionRoutine - Routine to be called when the IO finishes.
  338. OptionalParameter - Function code specific information
  339. Return Value:
  340. Status of the operation.
  341. --*/
  342. {
  343. ULONG PacketSize;
  344. PLMDR_REQUEST_PACKET RequestPacket = NULL;
  345. NTSTATUS NtStatus;
  346. PBROWSERASYNCCONTEXT Context = NULL;
  347. BOOL IssueAsyncRequest = FALSE;
  348. // Check to see if it is OK to issue an async IO request. We do not want to
  349. // issue these request can be issued.
  350. EnterCriticalSection(&BrAsyncIOCriticalSection);
  351. if (!BrDgShutDownInitiated) {
  352. BrDgAsyncIOsOutstanding += 1;
  353. IssueAsyncRequest = TRUE;
  354. }
  355. LeaveCriticalSection(&BrAsyncIOCriticalSection);
  356. if (!IssueAsyncRequest) {
  357. return ERROR_REQ_NOT_ACCEP;
  358. }
  359. //
  360. // Allocate a buffer for the context and the request packet.
  361. //
  362. PacketSize = sizeof(LMDR_REQUEST_PACKET) +
  363. MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR);
  364. if ( ARGUMENT_PRESENT(Network) ) {
  365. PacketSize +=
  366. Network->NetworkName.MaximumLength +
  367. Network->DomainInfo->DomUnicodeDomainNameString.Length;
  368. }
  369. Context = MIDL_user_allocate(sizeof(BROWSERASYNCCONTEXT) + PacketSize );
  370. if (Context == NULL) {
  371. BrDecrementOutstandingIos();
  372. return(ERROR_NOT_ENOUGH_MEMORY);
  373. }
  374. RequestPacket = (PLMDR_REQUEST_PACKET)(Context + 1);
  375. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  376. //
  377. // Set level to FALSE to indicate that find master should not initiate
  378. // a findmaster request, simply complete when a new master announces
  379. // itself.
  380. //
  381. RequestPacket->Level = 0;
  382. //
  383. // Fill in the network specific information if it is specified.
  384. //
  385. if ( ARGUMENT_PRESENT(Network) ) {
  386. //
  387. // Stick the name of the transport associated with this request at the
  388. // end of the request packet.
  389. //
  390. RequestPacket->TransportName.MaximumLength = Network->NetworkName.MaximumLength;
  391. RequestPacket->TransportName.Buffer = (PWSTR)((PCHAR)RequestPacket+sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)));
  392. RtlCopyUnicodeString(&RequestPacket->TransportName, &Network->NetworkName);
  393. //
  394. // Stick the domain name associated with this request at the
  395. // end of the request packet.
  396. //
  397. RequestPacket->EmulatedDomainName.MaximumLength = Network->DomainInfo->DomUnicodeDomainNameString.Length;
  398. RequestPacket->EmulatedDomainName.Length = 0;
  399. RequestPacket->EmulatedDomainName.Buffer = (PWSTR)(((PCHAR)RequestPacket->TransportName.Buffer) + RequestPacket->TransportName.MaximumLength);
  400. RtlAppendUnicodeToString(&RequestPacket->EmulatedDomainName, Network->DomainInfo->DomUnicodeDomainName );
  401. }
  402. //
  403. // Do opcode dependent initialization of the request packet.
  404. //
  405. switch ( ControlCode ) {
  406. case IOCTL_LMDR_NEW_MASTER_NAME:
  407. if (ARGUMENT_PRESENT(OptionalParameter)) {
  408. LPWSTR MasterName = (LPWSTR) OptionalParameter;
  409. RequestPacket->Parameters.GetMasterName.MasterNameLength =
  410. wcslen(MasterName+2)*sizeof(WCHAR);
  411. if ( RequestPacket->Parameters.GetMasterName.MasterNameLength > MAXIMUM_FILENAME_LENGTH ) {
  412. MIDL_user_free(Context);
  413. return ERROR_BUFFER_OVERFLOW;
  414. }
  415. wcscpy( RequestPacket->Parameters.GetMasterName.Name, MasterName+2);
  416. } else {
  417. RequestPacket->Parameters.GetMasterName.MasterNameLength = 0;
  418. }
  419. break;
  420. }
  421. //
  422. // Send the request to the bowser.
  423. //
  424. BrInitializeWorkItem(&Context->WorkItem, CompletionRoutine, Context);
  425. Context->Network = Network;
  426. Context->RequestPacket = RequestPacket;
  427. NtStatus = NtDeviceIoControlFile(BrDgReceiverDeviceHandle,
  428. NULL,
  429. CompleteAsyncBrowserIoControl,
  430. Context,
  431. &Context->IoStatusBlock,
  432. ControlCode,
  433. RequestPacket,
  434. PacketSize,
  435. RequestPacket,
  436. sizeof(LMDR_REQUEST_PACKET)+MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)
  437. );
  438. if (NT_ERROR(NtStatus)) {
  439. BrPrint(( BR_CRITICAL,
  440. "Unable to issue browser IoControl: %X\n", NtStatus));
  441. MIDL_user_free(Context);
  442. BrDecrementOutstandingIos();
  443. return(BrMapStatus(NtStatus));
  444. }
  445. return NERR_Success;
  446. }
  447. VOID
  448. CompleteAsyncBrowserIoControl(
  449. IN PVOID ApcContext,
  450. IN PIO_STATUS_BLOCK IoStatusBlock,
  451. IN ULONG Reserved
  452. )
  453. {
  454. PBROWSERASYNCCONTEXT Context = ApcContext;
  455. //
  456. // If this request was canceled, we're stopping the browser, so we
  457. // want to clean up our allocated pool. In addition, don't bother
  458. // calling into the routine - the threads are gone by now.
  459. //
  460. if (IoStatusBlock->Status == STATUS_CANCELLED) {
  461. MIDL_user_free(Context);
  462. // Signal the thread waiting on the completion in case of shut down
  463. // and reset the flag.
  464. BrDecrementOutstandingIos();
  465. return;
  466. }
  467. //
  468. // Timestamp when this request was completed. This allows us to tell
  469. // where a request spent its time.
  470. //
  471. NtQueryPerformanceCounter(&Context->TimeCompleted, NULL);
  472. BrQueueWorkItem(&Context->WorkItem);
  473. // Signal the thread waiting on the completion in case of shut down
  474. // and reset the flag.
  475. BrDecrementOutstandingIos();
  476. }
  477. NET_API_STATUS
  478. BrGetLocalBrowseList(
  479. IN PNETWORK Network,
  480. IN LPWSTR DomainName OPTIONAL,
  481. IN ULONG Level,
  482. IN ULONG ServerType,
  483. OUT PVOID *ServerList,
  484. OUT PULONG EntriesRead,
  485. OUT PULONG TotalEntries
  486. )
  487. {
  488. NET_API_STATUS status;
  489. PLMDR_REQUEST_PACKET Drp; // Datagram receiver request packet
  490. ULONG DrpSize;
  491. ULONG DomainNameSize;
  492. //
  493. // Allocate the request packet large enough to hold the variable length
  494. // domain name.
  495. //
  496. DomainNameSize = ARGUMENT_PRESENT(DomainName) ? (wcslen(DomainName) + 1) * sizeof(WCHAR) : 0;
  497. DrpSize = sizeof(LMDR_REQUEST_PACKET) +
  498. DomainNameSize +
  499. Network->NetworkName.MaximumLength +
  500. Network->DomainInfo->DomUnicodeDomainNameString.Length;
  501. if ((Drp = MIDL_user_allocate(DrpSize)) == NULL) {
  502. return GetLastError();
  503. }
  504. //
  505. // Set up request packet. Output buffer structure is of enumerate
  506. // servers type.
  507. //
  508. Drp->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  509. Drp->Type = EnumerateServers;
  510. Drp->Level = Level;
  511. Drp->Parameters.EnumerateServers.ServerType = ServerType;
  512. Drp->Parameters.EnumerateServers.ResumeHandle = 0;
  513. //
  514. // Copy the transport name into the buffer.
  515. //
  516. Drp->TransportName.Buffer = (PWSTR)((PCHAR)Drp+
  517. sizeof(LMDR_REQUEST_PACKET) +
  518. DomainNameSize);
  519. Drp->TransportName.MaximumLength = Network->NetworkName.MaximumLength;
  520. RtlCopyUnicodeString(&Drp->TransportName, &Network->NetworkName);
  521. //
  522. // Copy the enumalated domain name into the buffer.
  523. //
  524. Drp->EmulatedDomainName.MaximumLength = Network->DomainInfo->DomUnicodeDomainNameString.Length;
  525. Drp->EmulatedDomainName.Length = 0;
  526. Drp->EmulatedDomainName.Buffer = (PWSTR)(((PCHAR)Drp->TransportName.Buffer) + Drp->TransportName.MaximumLength);
  527. RtlAppendUnicodeToString(&Drp->EmulatedDomainName, Network->DomainInfo->DomUnicodeDomainName );
  528. //
  529. // Copy the queried domain name into the buffer.
  530. //
  531. if (ARGUMENT_PRESENT(DomainName)) {
  532. Drp->Parameters.EnumerateServers.DomainNameLength = DomainNameSize - sizeof(WCHAR);
  533. wcscpy(Drp->Parameters.EnumerateServers.DomainName, DomainName);
  534. } else {
  535. Drp->Parameters.EnumerateServers.DomainNameLength = 0;
  536. Drp->Parameters.EnumerateServers.DomainName[0] = '\0';
  537. }
  538. //
  539. // Ask the datagram receiver to enumerate the servers
  540. //
  541. status = DeviceControlGetInfo(
  542. BrDgReceiverDeviceHandle,
  543. IOCTL_LMDR_ENUMERATE_SERVERS,
  544. Drp,
  545. DrpSize,
  546. ServerList,
  547. 0xffffffff,
  548. 4096,
  549. NULL
  550. );
  551. *EntriesRead = Drp->Parameters.EnumerateServers.EntriesRead;
  552. *TotalEntries = Drp->Parameters.EnumerateServers.TotalEntries;
  553. (void) MIDL_user_free(Drp);
  554. BrPrint( (BR_CLIENT_OP,
  555. "BrGetLocalBrowseList: returning list got from Bowser for domain <%ws>, network <%ws>\n",
  556. DomainName, Network->NetworkName.Buffer ));
  557. return status;
  558. }
  559. NET_API_STATUS
  560. BrRemoveOtherDomain(
  561. IN PNETWORK Network,
  562. IN LPTSTR ServerName
  563. )
  564. {
  565. NET_API_STATUS Status;
  566. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
  567. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  568. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  569. RequestPacket->TransportName = Network->NetworkName;
  570. RequestPacket->EmulatedDomainName = Network->DomainInfo->DomUnicodeDomainNameString;
  571. RequestPacket->Parameters.AddDelName.DgReceiverNameLength = STRLEN(ServerName)*sizeof(TCHAR);
  572. RequestPacket->Parameters.AddDelName.Type = OtherDomain;
  573. if ( wcslen(ServerName) > LM20_CNLEN ) {
  574. return ERROR_BUFFER_OVERFLOW;
  575. }
  576. STRCPY(RequestPacket->Parameters.AddDelName.Name,ServerName);
  577. //
  578. // This is a simple IoControl - It just updates the status.
  579. //
  580. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  581. IOCTL_LMDR_DELETE_NAME_DOM,
  582. RequestPacket,
  583. sizeof(LMDR_REQUEST_PACKET),
  584. NULL,
  585. 0,
  586. NULL);
  587. return Status;
  588. }
  589. NET_API_STATUS
  590. BrAddName(
  591. IN PNETWORK Network,
  592. IN LPTSTR Name,
  593. IN DGRECEIVER_NAME_TYPE NameType
  594. )
  595. /*++
  596. Routine Description:
  597. Add a single name to a single transport.
  598. Arguments:
  599. Network - Transport to add the name to
  600. Name - Name to add
  601. NameType - Type of the name to add
  602. Return Value:
  603. None.
  604. --*/
  605. {
  606. NET_API_STATUS Status;
  607. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
  608. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  609. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  610. RequestPacket->TransportName = Network->NetworkName;
  611. RequestPacket->EmulatedDomainName = Network->DomainInfo->DomUnicodeDomainNameString;
  612. RequestPacket->Parameters.AddDelName.DgReceiverNameLength = STRLEN(Name)*sizeof(TCHAR);
  613. RequestPacket->Parameters.AddDelName.Type = NameType;
  614. STRCPY(RequestPacket->Parameters.AddDelName.Name,Name);
  615. //
  616. // This is a simple IoControl - It just updates the status.
  617. //
  618. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  619. IOCTL_LMDR_ADD_NAME_DOM,
  620. RequestPacket,
  621. sizeof(LMDR_REQUEST_PACKET),
  622. NULL,
  623. 0,
  624. NULL);
  625. return Status;
  626. }
  627. NET_API_STATUS
  628. BrQueryOtherDomains(
  629. OUT LPSERVER_INFO_100 *ReturnedBuffer,
  630. OUT LPDWORD TotalEntries
  631. )
  632. /*++
  633. Routine Description:
  634. This routine returns the list of "other domains" configured for this
  635. machine.
  636. Arguments:
  637. ReturnedBuffer - Returns the list of other domains as a SERVER_INFO_100 structure.
  638. TotalEntries - Returns the total number of other domains.
  639. Return Value:
  640. NET_API_STATUS - The status of this request.
  641. --*/
  642. {
  643. NET_API_STATUS Status;
  644. LMDR_REQUEST_PACKET RequestPacket;
  645. PDGRECEIVE_NAMES NameTable;
  646. PVOID Buffer;
  647. LPTSTR BufferEnd;
  648. PSERVER_INFO_100 ServerInfo;
  649. ULONG NumberOfOtherDomains;
  650. ULONG BufferSizeNeeded;
  651. ULONG i;
  652. RequestPacket.Type = EnumerateNames;
  653. RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  654. RequestPacket.Level = 0;
  655. RequestPacket.TransportName.Length = 0;
  656. RequestPacket.TransportName.Buffer = NULL;
  657. RtlInitUnicodeString( &RequestPacket.EmulatedDomainName, NULL );
  658. RequestPacket.Parameters.EnumerateNames.ResumeHandle = 0;
  659. Status = DeviceControlGetInfo(BrDgReceiverDeviceHandle,
  660. IOCTL_LMDR_ENUMERATE_NAMES,
  661. &RequestPacket,
  662. sizeof(RequestPacket),
  663. (LPVOID *)&NameTable,
  664. 0xffffffff,
  665. 0,
  666. NULL);
  667. if (Status != NERR_Success) {
  668. return Status;
  669. }
  670. NumberOfOtherDomains = 0;
  671. BufferSizeNeeded = 0;
  672. for (i = 0;i < RequestPacket.Parameters.EnumerateNames.EntriesRead ; i++) {
  673. if (NameTable[i].Type == OtherDomain) {
  674. NumberOfOtherDomains += 1;
  675. BufferSizeNeeded += sizeof(SERVER_INFO_100)+NameTable[i].DGReceiverName.Length+sizeof(TCHAR);
  676. }
  677. }
  678. *TotalEntries = NumberOfOtherDomains;
  679. Buffer = MIDL_user_allocate(BufferSizeNeeded);
  680. if (Buffer == NULL) {
  681. MIDL_user_free(NameTable);
  682. return(ERROR_NOT_ENOUGH_MEMORY);
  683. }
  684. ServerInfo = Buffer;
  685. BufferEnd = (LPTSTR)((PCHAR)Buffer+BufferSizeNeeded);
  686. for (i = 0;i < RequestPacket.Parameters.EnumerateNames.EntriesRead ; i++) {
  687. // Copy only OtherDomain names.
  688. // Protect from empty entries (in case transport name is empty).
  689. if (NameTable[i].Type == OtherDomain &&
  690. NameTable[i].DGReceiverName.Length != 0) {
  691. WCHAR NameBuffer[DNLEN+1];
  692. //
  693. // The name from the browser is not null terminated, so copy it
  694. // to a local buffer and null terminate it.
  695. //
  696. RtlCopyMemory(NameBuffer, NameTable[i].DGReceiverName.Buffer, NameTable[i].DGReceiverName.Length);
  697. NameBuffer[(NameTable[i].DGReceiverName.Length) / sizeof(TCHAR)] = UNICODE_NULL;
  698. ServerInfo->sv100_platform_id = PLATFORM_ID_OS2;
  699. ServerInfo->sv100_name = NameBuffer;
  700. if (!NetpPackString(&ServerInfo->sv100_name,
  701. (LPBYTE)(ServerInfo+1),
  702. &BufferEnd)) {
  703. MIDL_user_free(NameTable);
  704. return(NERR_InternalError);
  705. }
  706. ServerInfo += 1;
  707. }
  708. }
  709. MIDL_user_free(NameTable);
  710. *ReturnedBuffer = (LPSERVER_INFO_100) Buffer;
  711. Status = NERR_Success;
  712. return Status;
  713. }
  714. NET_API_STATUS
  715. BrAddOtherDomain(
  716. IN PNETWORK Network,
  717. IN LPTSTR ServerName
  718. )
  719. {
  720. return BrAddName( Network, ServerName, OtherDomain );
  721. }
  722. NET_API_STATUS
  723. BrBindToTransport(
  724. IN LPWSTR TransportName,
  725. IN LPWSTR EmulatedDomainName,
  726. IN LPWSTR EmulatedComputerName
  727. )
  728. {
  729. NET_API_STATUS Status;
  730. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH+1+CNLEN+1)*sizeof(WCHAR)];
  731. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  732. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  733. RequestPacket->Level = TRUE; // EmulatedComputerName follows transport name
  734. RequestPacket->TransportName.Length = 0;
  735. RequestPacket->TransportName.MaximumLength = 0;
  736. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, EmulatedDomainName );
  737. RequestPacket->Parameters.Bind.TransportNameLength = STRLEN(TransportName)*sizeof(TCHAR);
  738. if ( ( STRLEN(TransportName) > MAXIMUM_FILENAME_LENGTH ) ||
  739. ( STRLEN(EmulatedComputerName) > CNLEN ) ) {
  740. return ERROR_BUFFER_OVERFLOW;
  741. }
  742. STRCPY(RequestPacket->Parameters.Bind.TransportName, TransportName);
  743. STRCAT(RequestPacket->Parameters.Bind.TransportName, EmulatedComputerName );
  744. BrPrint(( BR_NETWORK,
  745. "%ws: %ws: bind from transport sent to bowser driver\n",
  746. EmulatedDomainName,
  747. TransportName));
  748. //
  749. // This is a simple IoControl - It just updates the status.
  750. //
  751. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  752. IOCTL_LMDR_BIND_TO_TRANSPORT_DOM,
  753. RequestPacket,
  754. FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.Bind.TransportName) +
  755. RequestPacket->Parameters.Bind.TransportNameLength +
  756. wcslen(EmulatedComputerName) * sizeof(WCHAR) + sizeof(WCHAR),
  757. NULL,
  758. 0,
  759. NULL);
  760. return Status;
  761. }
  762. NET_API_STATUS
  763. BrUnbindFromTransport(
  764. IN LPWSTR TransportName,
  765. IN LPWSTR EmulatedDomainName
  766. )
  767. {
  768. NET_API_STATUS Status;
  769. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH+1)*sizeof(WCHAR)];
  770. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  771. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  772. RequestPacket->TransportName.Length = 0;
  773. RequestPacket->TransportName.MaximumLength = 0;
  774. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, EmulatedDomainName );
  775. RequestPacket->Parameters.Unbind.TransportNameLength = STRLEN(TransportName)*sizeof(TCHAR);
  776. if ( RequestPacket->Parameters.Unbind.TransportNameLength > MAXIMUM_FILENAME_LENGTH ) {
  777. return ERROR_BUFFER_OVERFLOW;
  778. }
  779. STRCPY(RequestPacket->Parameters.Unbind.TransportName, TransportName);
  780. BrPrint(( BR_NETWORK,
  781. "%ws: %ws: unbind from transport sent to bowser driver\n",
  782. EmulatedDomainName,
  783. TransportName));
  784. //
  785. // This is a simple IoControl - It just updates the status.
  786. //
  787. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  788. IOCTL_LMDR_UNBIND_FROM_TRANSPORT_DOM,
  789. RequestPacket,
  790. FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.Bind.TransportName) +
  791. RequestPacket->Parameters.Bind.TransportNameLength,
  792. NULL,
  793. 0,
  794. NULL);
  795. if (Status != NERR_Success) {
  796. BrPrint(( BR_CRITICAL,
  797. "%ws: %ws: unbind from transport failed %ld\n",
  798. EmulatedDomainName,
  799. TransportName,
  800. Status ));
  801. }
  802. return Status;
  803. }
  804. NET_API_STATUS
  805. BrEnablePnp(
  806. BOOL Enable
  807. )
  808. /*++
  809. Routine Description:
  810. This routine enables or disables PNP messages from the bowser.
  811. Arguments:
  812. Enable - TRUE if messages are to be enabled.
  813. Return Value:
  814. None.
  815. --*/
  816. {
  817. NET_API_STATUS Status;
  818. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)];
  819. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  820. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  821. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  822. RtlInitUnicodeString( &RequestPacket->TransportName, NULL );
  823. RequestPacket->Parameters.NetlogonMailslotEnable.MaxMessageCount = Enable;
  824. //
  825. // This is a simple IoControl - It just updates the status.
  826. //
  827. Status = BrDgReceiverIoControl(
  828. BrDgReceiverDeviceHandle,
  829. IOCTL_LMDR_BROWSER_PNP_ENABLE,
  830. RequestPacket,
  831. sizeof(LMDR_REQUEST_PACKET),
  832. NULL,
  833. 0,
  834. NULL);
  835. if (Status != NERR_Success) {
  836. BrPrint(( BR_CRITICAL, "Enable PNP failed: %ld %ld\n", Enable, Status));
  837. }
  838. return Status;
  839. }
  840. VOID
  841. HandlePnpMessage (
  842. IN PVOID Ctx
  843. )
  844. /*++
  845. Routine Description:
  846. This function handles a PNP message from the bowser driver.
  847. Arguments:
  848. Ctx - Context block for request.
  849. Return Value:
  850. None.
  851. --*/
  852. {
  853. NET_API_STATUS NetStatus;
  854. PBROWSERASYNCCONTEXT Context = Ctx;
  855. PNETLOGON_MAILSLOT NetlogonMailslot =
  856. (PNETLOGON_MAILSLOT) Context->RequestPacket;
  857. LPWSTR Transport;
  858. UNICODE_STRING TransportName;
  859. LPWSTR HostedDomain = NULL;
  860. UNICODE_STRING HostedDomainName;
  861. NETLOGON_PNP_OPCODE PnpOpcode;
  862. ULONG TransportFlags;
  863. PLIST_ENTRY DomainEntry;
  864. PDOMAIN_INFO DomainInfo;
  865. PNETWORK Network;
  866. try {
  867. //
  868. // The request failed for some reason - just return immediately.
  869. //
  870. if (!NT_SUCCESS(Context->IoStatusBlock.Status)) {
  871. //
  872. // Sleep for a second to avoid consuming entire system.
  873. Sleep( 1000 );
  874. try_return(NOTHING);
  875. }
  876. //
  877. // If the message isn't a PNP message,
  878. // someone is really confused.
  879. //
  880. if ( NetlogonMailslot->MailslotNameSize != 0 ) {
  881. BrPrint(( BR_CRITICAL,
  882. "Got malformed PNP message\n" ));
  883. //
  884. // Sleep for a second to avoid consuming entire system.
  885. Sleep( 1000 );
  886. try_return(NOTHING);
  887. }
  888. //
  889. // Parse the message
  890. //
  891. PnpOpcode = NetlogonMailslot->MailslotNameOffset;
  892. TransportFlags = NetlogonMailslot->MailslotMessageOffset;
  893. if( NetlogonMailslot->TransportNameSize > 0 )
  894. {
  895. Transport = (LPWSTR) &(((LPBYTE)NetlogonMailslot)[
  896. NetlogonMailslot->TransportNameOffset]);
  897. RtlInitUnicodeString( &TransportName, Transport );
  898. }
  899. else
  900. {
  901. RtlInitUnicodeString( &TransportName, NULL );
  902. }
  903. if( NetlogonMailslot->DestinationNameSize > 0 )
  904. {
  905. HostedDomain = (LPWSTR) &(((LPBYTE)NetlogonMailslot)[
  906. NetlogonMailslot->DestinationNameOffset]);
  907. RtlInitUnicodeString( &HostedDomainName, HostedDomain );
  908. }
  909. else
  910. {
  911. RtlInitUnicodeString( &HostedDomainName, NULL );
  912. }
  913. //
  914. // Handle binding to a new network.
  915. //
  916. switch (PnpOpcode ) {
  917. case NlPnpTransportBind:
  918. BrPrint(( BR_NETWORK,
  919. "Received bind PNP opcode 0x%lx on transport: %ws\n",
  920. TransportFlags,
  921. Transport ));
  922. //
  923. // Ignore the direct host IPX transport.
  924. // The browser service created it so we don't need PNP notification.
  925. //
  926. if ( TransportFlags & LMDR_TRANSPORT_IPX ) {
  927. BrPrint(( BR_NETWORK,
  928. "Ignoring PNP bind of direct host IPX transport\n" ));
  929. break;
  930. }
  931. NetStatus = BrChangeConfigValue(
  932. L"DirectHostBinding",
  933. MultiSzType,
  934. NULL,
  935. &(BrInfo.DirectHostBinding),
  936. TRUE );
  937. if ( NetStatus != NERR_Success ) {
  938. BrPrint(( BR_CRITICAL,
  939. "Unbind failed to read Registry DirectHostBinding: %ws %ld\n",
  940. Transport,
  941. NetStatus ));
  942. //
  943. // Don't abort binding on failure to read DirectHostBinding, Our internal binding
  944. // info hasn't change so we'll use whatever we have.
  945. // Ignore error.
  946. //
  947. NetStatus = NERR_Success;
  948. } else {
  949. //
  950. // DirectHostBinding sepcified. Verify consistency & fail on
  951. // inconsistent setup (since it was setup, there was an intention resulted w/
  952. // a failure here).
  953. //
  954. EnterCriticalSection ( &BrInfo.ConfigCritSect );
  955. if (BrInfo.DirectHostBinding != NULL &&
  956. !NetpIsTStrArrayEmpty(BrInfo.DirectHostBinding)) {
  957. BrPrint(( BR_INIT,"DirectHostBinding length: %ld\n",NetpTStrArrayEntryCount(BrInfo.DirectHostBinding)));
  958. if (NetpTStrArrayEntryCount(BrInfo.DirectHostBinding) % 2 != 0) {
  959. NetApiBufferFree(BrInfo.DirectHostBinding);
  960. BrInfo.DirectHostBinding = NULL;
  961. // we fail on invalid specifications
  962. NetStatus = ERROR_INVALID_PARAMETER;
  963. }
  964. }
  965. LeaveCriticalSection ( &BrInfo.ConfigCritSect );
  966. }
  967. //
  968. // Loop creating the network for each emulated domain.
  969. //
  970. EnterCriticalSection(&NetworkCritSect);
  971. for (DomainEntry = ServicedDomains.Flink ;
  972. DomainEntry != &ServicedDomains;
  973. DomainEntry = DomainEntry->Flink ) {
  974. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  975. DomainInfo->PnpDone = FALSE;
  976. }
  977. for (DomainEntry = ServicedDomains.Flink ;
  978. DomainEntry != &ServicedDomains;
  979. ) {
  980. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  981. //
  982. // If this domain has already been processed,
  983. // skip it.
  984. //
  985. if ( DomainInfo->PnpDone ) {
  986. DomainEntry = DomainEntry->Flink;
  987. continue;
  988. }
  989. DomainInfo->PnpDone = TRUE;
  990. //
  991. // Drop the crit sect while doing the lenghty PNP operation.
  992. //
  993. DomainInfo->ReferenceCount++;
  994. LeaveCriticalSection(&NetworkCritSect);
  995. //
  996. // Finally create the transport.
  997. //
  998. NetStatus = BrCreateNetwork(
  999. &TransportName,
  1000. TransportFlags,
  1001. NULL,
  1002. DomainInfo );
  1003. if ( NetStatus != NERR_Success ) {
  1004. BrPrint(( BR_CRITICAL,
  1005. "%ws: Bind failed on transport: %ws %ld\n",
  1006. DomainInfo->DomUnicodeDomainName,
  1007. Transport,
  1008. NetStatus ));
  1009. // ?? Anything else to do on failure
  1010. }
  1011. //
  1012. // Finish process the emulated domains
  1013. // Start at the front of the list since we dropped the lock.
  1014. //
  1015. BrDereferenceDomain(DomainInfo);
  1016. EnterCriticalSection(&NetworkCritSect);
  1017. DomainEntry = ServicedDomains.Flink;
  1018. }
  1019. LeaveCriticalSection(&NetworkCritSect);
  1020. break;
  1021. //
  1022. // Handle Unbinding from a network.
  1023. //
  1024. case NlPnpTransportUnbind:
  1025. BrPrint(( BR_NETWORK,
  1026. "Received unbind PNP opcode 0x%lx on transport: %ws\n",
  1027. TransportFlags,
  1028. Transport ));
  1029. //
  1030. // Ignore the direct host IPX transport.
  1031. // The browser service created it so we don't need PNP notification.
  1032. //
  1033. if ( TransportFlags & LMDR_TRANSPORT_IPX ) {
  1034. BrPrint(( BR_NETWORK,
  1035. "Ignoring PNP unbind of direct host IPX transport\n" ));
  1036. break;
  1037. }
  1038. //
  1039. // Loop deleting the network for each emulated domain.
  1040. //
  1041. EnterCriticalSection(&NetworkCritSect);
  1042. for (DomainEntry = ServicedDomains.Flink ;
  1043. DomainEntry != &ServicedDomains;
  1044. DomainEntry = DomainEntry->Flink ) {
  1045. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  1046. DomainInfo->PnpDone = FALSE;
  1047. }
  1048. for (DomainEntry = ServicedDomains.Flink ;
  1049. DomainEntry != &ServicedDomains;
  1050. ) {
  1051. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  1052. //
  1053. // If this domain has already been processed,
  1054. // skip it.
  1055. //
  1056. if ( DomainInfo->PnpDone ) {
  1057. DomainEntry = DomainEntry->Flink;
  1058. continue;
  1059. }
  1060. DomainInfo->PnpDone = TRUE;
  1061. //
  1062. // Drop the crit sect while doing the lenghty PNP operation.
  1063. //
  1064. DomainInfo->ReferenceCount++;
  1065. LeaveCriticalSection(&NetworkCritSect);
  1066. //
  1067. // Finally delete the transport.
  1068. //
  1069. Network = BrFindNetwork( DomainInfo, &TransportName );
  1070. if ( Network == NULL ) {
  1071. BrPrint(( BR_CRITICAL,
  1072. "%ws: Unbind cannot find transport: %ws\n",
  1073. DomainInfo->DomUnicodeDomainName,
  1074. Transport ));
  1075. } else {
  1076. //
  1077. // If the network has an alternate network,
  1078. // delete it first.
  1079. //
  1080. if ( Network->AlternateNetwork != NULL ) {
  1081. PNETWORK AlternateNetwork;
  1082. AlternateNetwork = BrReferenceNetwork( Network->AlternateNetwork );
  1083. if ( AlternateNetwork != NULL) {
  1084. BrPrint(( BR_NETWORK,
  1085. "%ws: %ws: Unbind from alternate transport: %ws\n",
  1086. DomainInfo->DomUnicodeDomainName,
  1087. Transport,
  1088. AlternateNetwork->NetworkName.Buffer ));
  1089. NetStatus = BrDeleteNetwork(
  1090. AlternateNetwork,
  1091. NULL );
  1092. if ( NetStatus != NERR_Success ) {
  1093. BrPrint(( BR_CRITICAL,
  1094. "%ws: Unbind failed on transport: %ws %ld\n",
  1095. DomainInfo->DomUnicodeDomainName,
  1096. AlternateNetwork->NetworkName.Buffer,
  1097. NetStatus ));
  1098. // ?? Anything else to do on failure
  1099. }
  1100. BrDereferenceNetwork( AlternateNetwork );
  1101. }
  1102. }
  1103. //
  1104. // Delete the network.
  1105. //
  1106. NetStatus = BrDeleteNetwork(
  1107. Network,
  1108. NULL );
  1109. if ( NetStatus != NERR_Success ) {
  1110. BrPrint(( BR_CRITICAL,
  1111. "%ws: Unbind failed on transport: %ws %ld\n",
  1112. DomainInfo->DomUnicodeDomainName,
  1113. Transport,
  1114. NetStatus ));
  1115. // ?? Anything else to do on failure
  1116. }
  1117. BrDereferenceNetwork( Network );
  1118. }
  1119. //
  1120. // Finish process the emulated domains
  1121. // Start at the front of the list since we dropped the lock.
  1122. //
  1123. BrDereferenceDomain(DomainInfo);
  1124. EnterCriticalSection(&NetworkCritSect);
  1125. DomainEntry = ServicedDomains.Flink;
  1126. }
  1127. LeaveCriticalSection(&NetworkCritSect);
  1128. break;
  1129. //
  1130. // Handle domain rename
  1131. //
  1132. case NlPnpDomainRename:
  1133. BrPrint(( BR_NETWORK,
  1134. "Received Domain Rename PNP for domain: %ws\n", HostedDomain ));
  1135. //
  1136. // See if we're handling the specified domain.
  1137. //
  1138. DomainInfo = BrFindDomain( HostedDomain, FALSE );
  1139. if ( DomainInfo == NULL ) {
  1140. BrPrint(( BR_CRITICAL, "%ws: Renamed domain doesn't exist\n",
  1141. HostedDomain ));
  1142. } else {
  1143. //
  1144. // If so,
  1145. // rename it.
  1146. //
  1147. BrRenameDomain( DomainInfo );
  1148. BrDereferenceDomain( DomainInfo );
  1149. }
  1150. break;
  1151. //
  1152. // Handle PDC/BDC role change.
  1153. //
  1154. case NlPnpNewRole:
  1155. BrPrint(( BR_NETWORK,
  1156. "%ws: Received role change PNP opcode 0x%lx on transport: %ws\n",
  1157. HostedDomain,
  1158. TransportFlags,
  1159. Transport ));
  1160. //
  1161. // Role can only change on lanman NT systems
  1162. //
  1163. if (!BrInfo.IsLanmanNt) {
  1164. break;
  1165. }
  1166. //
  1167. // See if we're handling the specified domain.
  1168. //
  1169. DomainInfo = BrFindDomain( HostedDomain, FALSE );
  1170. if ( DomainInfo == NULL ) {
  1171. BrPrint(( BR_CRITICAL, "%ws: Hosted domain doesn't exist\n",
  1172. HostedDomain ));
  1173. } else {
  1174. //
  1175. // Find the specified network
  1176. //
  1177. Network = BrFindNetwork( DomainInfo, &TransportName );
  1178. if ( Network == NULL ) {
  1179. BrPrint(( BR_CRITICAL,
  1180. "%ws: Unbind cannot find transport: %ws\n",
  1181. DomainInfo->DomUnicodeDomainName,
  1182. Transport ));
  1183. } else {
  1184. if (LOCK_NETWORK(Network)) {
  1185. //
  1186. // Set the role to be PDC.
  1187. //
  1188. if ( TransportFlags & LMDR_TRANSPORT_PDC ) {
  1189. //
  1190. // If we think we're a BDC. Update our information.
  1191. //
  1192. if ( (Network->Flags & NETWORK_PDC) == 0 ) {
  1193. Network->Flags |= NETWORK_PDC;
  1194. //
  1195. // Make sure a GetMasterAnnouncement request is pending.
  1196. //
  1197. (VOID) PostGetMasterAnnouncement ( Network );
  1198. // Force an election to let the PDC win
  1199. (VOID) BrElectMasterOnNet( Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_ROLE_CHANGED );
  1200. }
  1201. //
  1202. // Set the role to BDC.
  1203. //
  1204. } else {
  1205. //
  1206. // We think we're the PDC. Update our information.
  1207. //
  1208. if ( Network->Flags & NETWORK_PDC ) {
  1209. Network->Flags &= ~NETWORK_PDC;
  1210. // Force an election to let the PDC win
  1211. (VOID) BrElectMasterOnNet( Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_ROLE_CHANGED );
  1212. }
  1213. }
  1214. UNLOCK_NETWORK(Network);
  1215. }
  1216. BrDereferenceNetwork( Network );
  1217. }
  1218. BrDereferenceDomain( DomainInfo );
  1219. }
  1220. break;
  1221. //
  1222. // Ignore new Ip Addresses
  1223. //
  1224. case NlPnpNewIpAddress:
  1225. BrPrint(( BR_NETWORK,
  1226. "Received IP address change PNP opcode 0x%lx on transport: %ws\n",
  1227. TransportFlags,
  1228. Transport ));
  1229. break;
  1230. default:
  1231. BrPrint(( BR_CRITICAL,
  1232. "Received invalid PNP opcode 0x%x on transport: %ws\n",
  1233. PnpOpcode,
  1234. Transport ));
  1235. break;
  1236. }
  1237. try_exit:NOTHING;
  1238. } finally {
  1239. MIDL_user_free(Context);
  1240. //
  1241. // Always finish by asking for another PNP message.
  1242. //
  1243. // For PNP, it is fine to only process a single PNP message at a time.
  1244. // If this message mechanism starts being used for other purposes,
  1245. // we may want to immediately ask for another message upon receipt
  1246. // of this one.
  1247. //
  1248. while ((NetStatus = PostWaitForPnp()) != NERR_Success ) {
  1249. BrPrint(( BR_CRITICAL,
  1250. "Unable to re-issue PostWaitForPnp request (waiting): %ld\n",
  1251. NetStatus));
  1252. //
  1253. // On error, wait a second before returning. This ensures we don't
  1254. // consume the system in an infinite loop. We don't shutdown
  1255. // because the error might be a temporary low memory condition.
  1256. //
  1257. NetStatus = WaitForSingleObject( BrGlobalData.TerminateNowEvent, 1000 );
  1258. if ( NetStatus != WAIT_TIMEOUT ) {
  1259. BrPrint(( BR_CRITICAL,
  1260. "Not re-issuing PostWaitForPnp request since we're terminating: %ld\n",
  1261. NetStatus));
  1262. break;
  1263. }
  1264. }
  1265. }
  1266. return;
  1267. }
  1268. NET_API_STATUS
  1269. PostWaitForPnp (
  1270. VOID
  1271. )
  1272. /*++
  1273. Routine Description:
  1274. This function issues and async call to the bowser driver asking
  1275. it to inform us of PNP events.
  1276. Arguments:
  1277. None.
  1278. Return Value:
  1279. Status - The status of the operation.
  1280. --*/
  1281. {
  1282. return BrIssueAsyncBrowserIoControl(
  1283. NULL,
  1284. IOCTL_LMDR_BROWSER_PNP_READ,
  1285. HandlePnpMessage,
  1286. NULL );
  1287. }