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.

1720 lines
51 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. wcscpy( RequestPacket->Parameters.GetMasterName.Name, MasterName+2);
  412. } else {
  413. RequestPacket->Parameters.GetMasterName.MasterNameLength = 0;
  414. }
  415. break;
  416. }
  417. //
  418. // Send the request to the bowser.
  419. //
  420. BrInitializeWorkItem(&Context->WorkItem, CompletionRoutine, Context);
  421. Context->Network = Network;
  422. Context->RequestPacket = RequestPacket;
  423. NtStatus = NtDeviceIoControlFile(BrDgReceiverDeviceHandle,
  424. NULL,
  425. CompleteAsyncBrowserIoControl,
  426. Context,
  427. &Context->IoStatusBlock,
  428. ControlCode,
  429. RequestPacket,
  430. PacketSize,
  431. RequestPacket,
  432. sizeof(LMDR_REQUEST_PACKET)+MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)
  433. );
  434. if (NT_ERROR(NtStatus)) {
  435. BrPrint(( BR_CRITICAL,
  436. "Unable to issue browser IoControl: %X\n", NtStatus));
  437. MIDL_user_free(Context);
  438. BrDecrementOutstandingIos();
  439. return(BrMapStatus(NtStatus));
  440. }
  441. return NERR_Success;
  442. }
  443. VOID
  444. CompleteAsyncBrowserIoControl(
  445. IN PVOID ApcContext,
  446. IN PIO_STATUS_BLOCK IoStatusBlock,
  447. IN ULONG Reserved
  448. )
  449. {
  450. PBROWSERASYNCCONTEXT Context = ApcContext;
  451. //
  452. // If this request was canceled, we're stopping the browser, so we
  453. // want to clean up our allocated pool. In addition, don't bother
  454. // calling into the routine - the threads are gone by now.
  455. //
  456. if (IoStatusBlock->Status == STATUS_CANCELLED) {
  457. MIDL_user_free(Context);
  458. // Signal the thread waiting on the completion in case of shut down
  459. // and reset the flag.
  460. BrDecrementOutstandingIos();
  461. return;
  462. }
  463. //
  464. // Timestamp when this request was completed. This allows us to tell
  465. // where a request spent its time.
  466. //
  467. NtQueryPerformanceCounter(&Context->TimeCompleted, NULL);
  468. BrQueueWorkItem(&Context->WorkItem);
  469. // Signal the thread waiting on the completion in case of shut down
  470. // and reset the flag.
  471. BrDecrementOutstandingIos();
  472. }
  473. NET_API_STATUS
  474. BrGetLocalBrowseList(
  475. IN PNETWORK Network,
  476. IN LPWSTR DomainName OPTIONAL,
  477. IN ULONG Level,
  478. IN ULONG ServerType,
  479. OUT PVOID *ServerList,
  480. OUT PULONG EntriesRead,
  481. OUT PULONG TotalEntries
  482. )
  483. {
  484. NET_API_STATUS status;
  485. PLMDR_REQUEST_PACKET Drp; // Datagram receiver request packet
  486. ULONG DrpSize;
  487. ULONG DomainNameSize;
  488. //
  489. // Allocate the request packet large enough to hold the variable length
  490. // domain name.
  491. //
  492. DomainNameSize = ARGUMENT_PRESENT(DomainName) ? (wcslen(DomainName) + 1) * sizeof(WCHAR) : 0;
  493. DrpSize = sizeof(LMDR_REQUEST_PACKET) +
  494. DomainNameSize +
  495. Network->NetworkName.MaximumLength +
  496. Network->DomainInfo->DomUnicodeDomainNameString.Length;
  497. if ((Drp = MIDL_user_allocate(DrpSize)) == NULL) {
  498. return GetLastError();
  499. }
  500. //
  501. // Set up request packet. Output buffer structure is of enumerate
  502. // servers type.
  503. //
  504. Drp->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  505. Drp->Type = EnumerateServers;
  506. Drp->Level = Level;
  507. Drp->Parameters.EnumerateServers.ServerType = ServerType;
  508. Drp->Parameters.EnumerateServers.ResumeHandle = 0;
  509. //
  510. // Copy the transport name into the buffer.
  511. //
  512. Drp->TransportName.Buffer = (PWSTR)((PCHAR)Drp+
  513. sizeof(LMDR_REQUEST_PACKET) +
  514. DomainNameSize);
  515. Drp->TransportName.MaximumLength = Network->NetworkName.MaximumLength;
  516. RtlCopyUnicodeString(&Drp->TransportName, &Network->NetworkName);
  517. //
  518. // Copy the enumalated domain name into the buffer.
  519. //
  520. Drp->EmulatedDomainName.MaximumLength = Network->DomainInfo->DomUnicodeDomainNameString.Length;
  521. Drp->EmulatedDomainName.Length = 0;
  522. Drp->EmulatedDomainName.Buffer = (PWSTR)(((PCHAR)Drp->TransportName.Buffer) + Drp->TransportName.MaximumLength);
  523. RtlAppendUnicodeToString(&Drp->EmulatedDomainName, Network->DomainInfo->DomUnicodeDomainName );
  524. //
  525. // Copy the queried domain name into the buffer.
  526. //
  527. if (ARGUMENT_PRESENT(DomainName)) {
  528. Drp->Parameters.EnumerateServers.DomainNameLength = DomainNameSize - sizeof(WCHAR);
  529. wcscpy(Drp->Parameters.EnumerateServers.DomainName, DomainName);
  530. } else {
  531. Drp->Parameters.EnumerateServers.DomainNameLength = 0;
  532. Drp->Parameters.EnumerateServers.DomainName[0] = '\0';
  533. }
  534. //
  535. // Ask the datagram receiver to enumerate the servers
  536. //
  537. status = DeviceControlGetInfo(
  538. BrDgReceiverDeviceHandle,
  539. IOCTL_LMDR_ENUMERATE_SERVERS,
  540. Drp,
  541. DrpSize,
  542. ServerList,
  543. 0xffffffff,
  544. 4096,
  545. NULL
  546. );
  547. *EntriesRead = Drp->Parameters.EnumerateServers.EntriesRead;
  548. *TotalEntries = Drp->Parameters.EnumerateServers.TotalEntries;
  549. (void) MIDL_user_free(Drp);
  550. return status;
  551. }
  552. NET_API_STATUS
  553. BrRemoveOtherDomain(
  554. IN PNETWORK Network,
  555. IN LPTSTR ServerName
  556. )
  557. {
  558. NET_API_STATUS Status;
  559. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
  560. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  561. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  562. RequestPacket->TransportName = Network->NetworkName;
  563. RequestPacket->EmulatedDomainName = Network->DomainInfo->DomUnicodeDomainNameString;
  564. RequestPacket->Parameters.AddDelName.DgReceiverNameLength = STRLEN(ServerName)*sizeof(TCHAR);
  565. RequestPacket->Parameters.AddDelName.Type = OtherDomain;
  566. STRCPY(RequestPacket->Parameters.AddDelName.Name,ServerName);
  567. //
  568. // This is a simple IoControl - It just updates the status.
  569. //
  570. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  571. IOCTL_LMDR_DELETE_NAME_DOM,
  572. RequestPacket,
  573. sizeof(LMDR_REQUEST_PACKET),
  574. NULL,
  575. 0,
  576. NULL);
  577. return Status;
  578. }
  579. NET_API_STATUS
  580. BrAddName(
  581. IN PNETWORK Network,
  582. IN LPTSTR Name,
  583. IN DGRECEIVER_NAME_TYPE NameType
  584. )
  585. /*++
  586. Routine Description:
  587. Add a single name to a single transport.
  588. Arguments:
  589. Network - Transport to add the name to
  590. Name - Name to add
  591. NameType - Type of the name to add
  592. Return Value:
  593. None.
  594. --*/
  595. {
  596. NET_API_STATUS Status;
  597. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
  598. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  599. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  600. RequestPacket->TransportName = Network->NetworkName;
  601. RequestPacket->EmulatedDomainName = Network->DomainInfo->DomUnicodeDomainNameString;
  602. RequestPacket->Parameters.AddDelName.DgReceiverNameLength = STRLEN(Name)*sizeof(TCHAR);
  603. RequestPacket->Parameters.AddDelName.Type = NameType;
  604. STRCPY(RequestPacket->Parameters.AddDelName.Name,Name);
  605. //
  606. // This is a simple IoControl - It just updates the status.
  607. //
  608. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  609. IOCTL_LMDR_ADD_NAME_DOM,
  610. RequestPacket,
  611. sizeof(LMDR_REQUEST_PACKET),
  612. NULL,
  613. 0,
  614. NULL);
  615. return Status;
  616. }
  617. NET_API_STATUS
  618. BrQueryOtherDomains(
  619. OUT LPSERVER_INFO_100 *ReturnedBuffer,
  620. OUT LPDWORD TotalEntries
  621. )
  622. /*++
  623. Routine Description:
  624. This routine returns the list of "other domains" configured for this
  625. machine.
  626. Arguments:
  627. ReturnedBuffer - Returns the list of other domains as a SERVER_INFO_100 structure.
  628. TotalEntries - Returns the total number of other domains.
  629. Return Value:
  630. NET_API_STATUS - The status of this request.
  631. --*/
  632. {
  633. NET_API_STATUS Status;
  634. LMDR_REQUEST_PACKET RequestPacket;
  635. PDGRECEIVE_NAMES NameTable;
  636. PVOID Buffer;
  637. LPTSTR BufferEnd;
  638. PSERVER_INFO_100 ServerInfo;
  639. ULONG NumberOfOtherDomains;
  640. ULONG BufferSizeNeeded;
  641. ULONG i;
  642. RequestPacket.Type = EnumerateNames;
  643. RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  644. RequestPacket.Level = 0;
  645. RequestPacket.TransportName.Length = 0;
  646. RequestPacket.TransportName.Buffer = NULL;
  647. RtlInitUnicodeString( &RequestPacket.EmulatedDomainName, NULL );
  648. RequestPacket.Parameters.EnumerateNames.ResumeHandle = 0;
  649. Status = DeviceControlGetInfo(BrDgReceiverDeviceHandle,
  650. IOCTL_LMDR_ENUMERATE_NAMES,
  651. &RequestPacket,
  652. sizeof(RequestPacket),
  653. (LPVOID *)&NameTable,
  654. 0xffffffff,
  655. 0,
  656. NULL);
  657. if (Status != NERR_Success) {
  658. return Status;
  659. }
  660. NumberOfOtherDomains = 0;
  661. BufferSizeNeeded = 0;
  662. for (i = 0;i < RequestPacket.Parameters.EnumerateNames.EntriesRead ; i++) {
  663. if (NameTable[i].Type == OtherDomain) {
  664. NumberOfOtherDomains += 1;
  665. BufferSizeNeeded += sizeof(SERVER_INFO_100)+NameTable[i].DGReceiverName.Length+sizeof(TCHAR);
  666. }
  667. }
  668. *TotalEntries = NumberOfOtherDomains;
  669. Buffer = MIDL_user_allocate(BufferSizeNeeded);
  670. if (Buffer == NULL) {
  671. MIDL_user_free(NameTable);
  672. return(ERROR_NOT_ENOUGH_MEMORY);
  673. }
  674. ServerInfo = Buffer;
  675. BufferEnd = (LPTSTR)((PCHAR)Buffer+BufferSizeNeeded);
  676. for (i = 0;i < RequestPacket.Parameters.EnumerateNames.EntriesRead ; i++) {
  677. // Copy only OtherDomain names.
  678. // Protect from empty entries (in case transport name is empty).
  679. if (NameTable[i].Type == OtherDomain &&
  680. NameTable[i].DGReceiverName.Length != 0) {
  681. WCHAR NameBuffer[DNLEN+1];
  682. //
  683. // The name from the browser is not null terminated, so copy it
  684. // to a local buffer and null terminate it.
  685. //
  686. RtlCopyMemory(NameBuffer, NameTable[i].DGReceiverName.Buffer, NameTable[i].DGReceiverName.Length);
  687. NameBuffer[(NameTable[i].DGReceiverName.Length) / sizeof(TCHAR)] = UNICODE_NULL;
  688. ServerInfo->sv100_platform_id = PLATFORM_ID_OS2;
  689. ServerInfo->sv100_name = NameBuffer;
  690. if (!NetpPackString(&ServerInfo->sv100_name,
  691. (LPBYTE)(ServerInfo+1),
  692. &BufferEnd)) {
  693. MIDL_user_free(NameTable);
  694. return(NERR_InternalError);
  695. }
  696. ServerInfo += 1;
  697. }
  698. }
  699. MIDL_user_free(NameTable);
  700. *ReturnedBuffer = (LPSERVER_INFO_100) Buffer;
  701. Status = NERR_Success;
  702. return Status;
  703. }
  704. NET_API_STATUS
  705. BrAddOtherDomain(
  706. IN PNETWORK Network,
  707. IN LPTSTR ServerName
  708. )
  709. {
  710. return BrAddName( Network, ServerName, OtherDomain );
  711. }
  712. NET_API_STATUS
  713. BrBindToTransport(
  714. IN LPWSTR TransportName,
  715. IN LPWSTR EmulatedDomainName,
  716. IN LPWSTR EmulatedComputerName
  717. )
  718. {
  719. NET_API_STATUS Status;
  720. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH+1+CNLEN+1)*sizeof(WCHAR)];
  721. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  722. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  723. RequestPacket->Level = TRUE; // EmulatedComputerName follows transport name
  724. RequestPacket->TransportName.Length = 0;
  725. RequestPacket->TransportName.MaximumLength = 0;
  726. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, EmulatedDomainName );
  727. RequestPacket->Parameters.Bind.TransportNameLength = STRLEN(TransportName)*sizeof(TCHAR);
  728. STRCPY(RequestPacket->Parameters.Bind.TransportName, TransportName);
  729. STRCAT(RequestPacket->Parameters.Bind.TransportName, EmulatedComputerName );
  730. BrPrint(( BR_NETWORK,
  731. "%ws: %ws: bind from transport sent to bowser driver\n",
  732. EmulatedDomainName,
  733. TransportName));
  734. //
  735. // This is a simple IoControl - It just updates the status.
  736. //
  737. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  738. IOCTL_LMDR_BIND_TO_TRANSPORT_DOM,
  739. RequestPacket,
  740. FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.Bind.TransportName) +
  741. RequestPacket->Parameters.Bind.TransportNameLength +
  742. wcslen(EmulatedComputerName) * sizeof(WCHAR) + sizeof(WCHAR),
  743. NULL,
  744. 0,
  745. NULL);
  746. return Status;
  747. }
  748. NET_API_STATUS
  749. BrUnbindFromTransport(
  750. IN LPWSTR TransportName,
  751. IN LPWSTR EmulatedDomainName
  752. )
  753. {
  754. NET_API_STATUS Status;
  755. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH+1)*sizeof(WCHAR)];
  756. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  757. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  758. RequestPacket->TransportName.Length = 0;
  759. RequestPacket->TransportName.MaximumLength = 0;
  760. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, EmulatedDomainName );
  761. RequestPacket->Parameters.Unbind.TransportNameLength = STRLEN(TransportName)*sizeof(TCHAR);
  762. STRCPY(RequestPacket->Parameters.Unbind.TransportName, TransportName);
  763. BrPrint(( BR_NETWORK,
  764. "%ws: %ws: unbind from transport sent to bowser driver\n",
  765. EmulatedDomainName,
  766. TransportName));
  767. //
  768. // This is a simple IoControl - It just updates the status.
  769. //
  770. Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
  771. IOCTL_LMDR_UNBIND_FROM_TRANSPORT_DOM,
  772. RequestPacket,
  773. FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.Bind.TransportName) +
  774. RequestPacket->Parameters.Bind.TransportNameLength,
  775. NULL,
  776. 0,
  777. NULL);
  778. if (Status != NERR_Success) {
  779. BrPrint(( BR_CRITICAL,
  780. "%ws: %ws: unbind from transport failed %ld\n",
  781. EmulatedDomainName,
  782. TransportName,
  783. Status ));
  784. }
  785. return Status;
  786. }
  787. NET_API_STATUS
  788. BrEnablePnp(
  789. BOOL Enable
  790. )
  791. /*++
  792. Routine Description:
  793. This routine enables or disables PNP messages from the bowser.
  794. Arguments:
  795. Enable - TRUE if messages are to be enabled.
  796. Return Value:
  797. None.
  798. --*/
  799. {
  800. NET_API_STATUS Status;
  801. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)];
  802. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  803. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  804. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  805. RtlInitUnicodeString( &RequestPacket->TransportName, NULL );
  806. RequestPacket->Parameters.NetlogonMailslotEnable.MaxMessageCount = Enable;
  807. //
  808. // This is a simple IoControl - It just updates the status.
  809. //
  810. Status = BrDgReceiverIoControl(
  811. BrDgReceiverDeviceHandle,
  812. IOCTL_LMDR_BROWSER_PNP_ENABLE,
  813. RequestPacket,
  814. sizeof(LMDR_REQUEST_PACKET),
  815. NULL,
  816. 0,
  817. NULL);
  818. if (Status != NERR_Success) {
  819. BrPrint(( BR_CRITICAL, "Enable PNP failed: %ld %ld\n", Enable, Status));
  820. }
  821. return Status;
  822. }
  823. VOID
  824. HandlePnpMessage (
  825. IN PVOID Ctx
  826. )
  827. /*++
  828. Routine Description:
  829. This function handles a PNP message from the bowser driver.
  830. Arguments:
  831. Ctx - Context block for request.
  832. Return Value:
  833. None.
  834. --*/
  835. {
  836. NET_API_STATUS NetStatus;
  837. PBROWSERASYNCCONTEXT Context = Ctx;
  838. PNETLOGON_MAILSLOT NetlogonMailslot =
  839. (PNETLOGON_MAILSLOT) Context->RequestPacket;
  840. LPWSTR Transport;
  841. UNICODE_STRING TransportName;
  842. LPWSTR HostedDomain;
  843. UNICODE_STRING HostedDomainName;
  844. NETLOGON_PNP_OPCODE PnpOpcode;
  845. ULONG TransportFlags;
  846. PLIST_ENTRY DomainEntry;
  847. PDOMAIN_INFO DomainInfo;
  848. PNETWORK Network;
  849. try {
  850. //
  851. // The request failed for some reason - just return immediately.
  852. //
  853. if (!NT_SUCCESS(Context->IoStatusBlock.Status)) {
  854. //
  855. // Sleep for a second to avoid consuming entire system.
  856. Sleep( 1000 );
  857. try_return(NOTHING);
  858. }
  859. //
  860. // If the message isn't a PNP message,
  861. // someone is really confused.
  862. //
  863. if ( NetlogonMailslot->MailslotNameSize != 0 ) {
  864. BrPrint(( BR_CRITICAL,
  865. "Got malformed PNP message\n" ));
  866. //
  867. // Sleep for a second to avoid consuming entire system.
  868. Sleep( 1000 );
  869. try_return(NOTHING);
  870. }
  871. //
  872. // Parse the message
  873. //
  874. PnpOpcode = NetlogonMailslot->MailslotNameOffset;
  875. TransportFlags = NetlogonMailslot->MailslotMessageOffset;
  876. if( NetlogonMailslot->TransportNameSize > 0 )
  877. {
  878. Transport = (LPWSTR) &(((LPBYTE)NetlogonMailslot)[
  879. NetlogonMailslot->TransportNameOffset]);
  880. RtlInitUnicodeString( &TransportName, Transport );
  881. }
  882. else
  883. {
  884. RtlInitUnicodeString( &TransportName, NULL );
  885. }
  886. if( NetlogonMailslot->DestinationNameSize > 0 )
  887. {
  888. HostedDomain = (LPWSTR) &(((LPBYTE)NetlogonMailslot)[
  889. NetlogonMailslot->DestinationNameOffset]);
  890. RtlInitUnicodeString( &HostedDomainName, HostedDomain );
  891. }
  892. else
  893. {
  894. RtlInitUnicodeString( &HostedDomainName, NULL );
  895. }
  896. //
  897. // Handle binding to a new network.
  898. //
  899. switch (PnpOpcode ) {
  900. case NlPnpTransportBind:
  901. BrPrint(( BR_NETWORK,
  902. "Received bind PNP opcode 0x%lx on transport: %ws\n",
  903. TransportFlags,
  904. Transport ));
  905. //
  906. // Ignore the direct host IPX transport.
  907. // The browser service created it so we don't need PNP notification.
  908. //
  909. if ( TransportFlags & LMDR_TRANSPORT_IPX ) {
  910. BrPrint(( BR_NETWORK,
  911. "Ignoring PNP bind of direct host IPX transport\n" ));
  912. break;
  913. }
  914. NetStatus = BrChangeConfigValue(
  915. L"DirectHostBinding",
  916. MultiSzType,
  917. NULL,
  918. &(BrInfo.DirectHostBinding),
  919. TRUE );
  920. if ( NetStatus != NERR_Success ) {
  921. BrPrint(( BR_CRITICAL,
  922. "Unbind failed to read Registry DirectHostBinding: %ws %ld\n",
  923. Transport,
  924. NetStatus ));
  925. //
  926. // Don't abort binding on failure to read DirectHostBinding, Our internal binding
  927. // info hasn't change so we'll use whatever we have.
  928. // Ignore error.
  929. //
  930. NetStatus = NERR_Success;
  931. } else {
  932. //
  933. // DirectHostBinding sepcified. Verify consistency & fail on
  934. // inconsistent setup (since it was setup, there was an intention resulted w/
  935. // a failure here).
  936. //
  937. EnterCriticalSection ( &BrInfo.ConfigCritSect );
  938. if (BrInfo.DirectHostBinding != NULL &&
  939. !NetpIsTStrArrayEmpty(BrInfo.DirectHostBinding)) {
  940. BrPrint(( BR_INIT,"DirectHostBinding length: %ld\n",NetpTStrArrayEntryCount(BrInfo.DirectHostBinding)));
  941. if (NetpTStrArrayEntryCount(BrInfo.DirectHostBinding) % 2 != 0) {
  942. NetApiBufferFree(BrInfo.DirectHostBinding);
  943. BrInfo.DirectHostBinding = NULL;
  944. // we fail on invalid specifications
  945. NetStatus = ERROR_INVALID_PARAMETER;
  946. }
  947. }
  948. LeaveCriticalSection ( &BrInfo.ConfigCritSect );
  949. }
  950. //
  951. // Loop creating the network for each emulated domain.
  952. //
  953. EnterCriticalSection(&NetworkCritSect);
  954. for (DomainEntry = ServicedDomains.Flink ;
  955. DomainEntry != &ServicedDomains;
  956. DomainEntry = DomainEntry->Flink ) {
  957. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  958. DomainInfo->PnpDone = FALSE;
  959. }
  960. for (DomainEntry = ServicedDomains.Flink ;
  961. DomainEntry != &ServicedDomains;
  962. ) {
  963. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  964. //
  965. // If this domain has already been processed,
  966. // skip it.
  967. //
  968. if ( DomainInfo->PnpDone ) {
  969. DomainEntry = DomainEntry->Flink;
  970. continue;
  971. }
  972. DomainInfo->PnpDone = TRUE;
  973. //
  974. // Drop the crit sect while doing the lenghty PNP operation.
  975. //
  976. DomainInfo->ReferenceCount++;
  977. LeaveCriticalSection(&NetworkCritSect);
  978. //
  979. // Finally create the transport.
  980. //
  981. NetStatus = BrCreateNetwork(
  982. &TransportName,
  983. TransportFlags,
  984. NULL,
  985. DomainInfo );
  986. if ( NetStatus != NERR_Success ) {
  987. BrPrint(( BR_CRITICAL,
  988. "%ws: Bind failed on transport: %ws %ld\n",
  989. DomainInfo->DomUnicodeDomainName,
  990. Transport,
  991. NetStatus ));
  992. // ?? Anything else to do on failure
  993. }
  994. //
  995. // Finish process the emulated domains
  996. // Start at the front of the list since we dropped the lock.
  997. //
  998. BrDereferenceDomain(DomainInfo);
  999. EnterCriticalSection(&NetworkCritSect);
  1000. DomainEntry = ServicedDomains.Flink;
  1001. }
  1002. LeaveCriticalSection(&NetworkCritSect);
  1003. break;
  1004. //
  1005. // Handle Unbinding from a network.
  1006. //
  1007. case NlPnpTransportUnbind:
  1008. BrPrint(( BR_NETWORK,
  1009. "Received unbind PNP opcode 0x%lx on transport: %ws\n",
  1010. TransportFlags,
  1011. Transport ));
  1012. //
  1013. // Ignore the direct host IPX transport.
  1014. // The browser service created it so we don't need PNP notification.
  1015. //
  1016. if ( TransportFlags & LMDR_TRANSPORT_IPX ) {
  1017. BrPrint(( BR_NETWORK,
  1018. "Ignoring PNP unbind of direct host IPX transport\n" ));
  1019. break;
  1020. }
  1021. //
  1022. // Loop deleting the network for each emulated domain.
  1023. //
  1024. EnterCriticalSection(&NetworkCritSect);
  1025. for (DomainEntry = ServicedDomains.Flink ;
  1026. DomainEntry != &ServicedDomains;
  1027. DomainEntry = DomainEntry->Flink ) {
  1028. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  1029. DomainInfo->PnpDone = FALSE;
  1030. }
  1031. for (DomainEntry = ServicedDomains.Flink ;
  1032. DomainEntry != &ServicedDomains;
  1033. ) {
  1034. DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
  1035. //
  1036. // If this domain has already been processed,
  1037. // skip it.
  1038. //
  1039. if ( DomainInfo->PnpDone ) {
  1040. DomainEntry = DomainEntry->Flink;
  1041. continue;
  1042. }
  1043. DomainInfo->PnpDone = TRUE;
  1044. //
  1045. // Drop the crit sect while doing the lenghty PNP operation.
  1046. //
  1047. DomainInfo->ReferenceCount++;
  1048. LeaveCriticalSection(&NetworkCritSect);
  1049. //
  1050. // Finally delete the transport.
  1051. //
  1052. Network = BrFindNetwork( DomainInfo, &TransportName );
  1053. if ( Network == NULL ) {
  1054. BrPrint(( BR_CRITICAL,
  1055. "%ws: Unbind cannot find transport: %ws\n",
  1056. DomainInfo->DomUnicodeDomainName,
  1057. Transport ));
  1058. } else {
  1059. //
  1060. // If the network has an alternate network,
  1061. // delete it first.
  1062. //
  1063. if ( Network->AlternateNetwork != NULL ) {
  1064. PNETWORK AlternateNetwork;
  1065. AlternateNetwork = BrReferenceNetwork( Network->AlternateNetwork );
  1066. if ( AlternateNetwork != NULL) {
  1067. BrPrint(( BR_NETWORK,
  1068. "%ws: %ws: Unbind from alternate transport: %ws\n",
  1069. DomainInfo->DomUnicodeDomainName,
  1070. Transport,
  1071. AlternateNetwork->NetworkName.Buffer ));
  1072. NetStatus = BrDeleteNetwork(
  1073. AlternateNetwork,
  1074. NULL );
  1075. if ( NetStatus != NERR_Success ) {
  1076. BrPrint(( BR_CRITICAL,
  1077. "%ws: Unbind failed on transport: %ws %ld\n",
  1078. DomainInfo->DomUnicodeDomainName,
  1079. AlternateNetwork->NetworkName.Buffer,
  1080. NetStatus ));
  1081. // ?? Anything else to do on failure
  1082. }
  1083. BrDereferenceNetwork( AlternateNetwork );
  1084. }
  1085. }
  1086. //
  1087. // Delete the network.
  1088. //
  1089. NetStatus = BrDeleteNetwork(
  1090. Network,
  1091. NULL );
  1092. if ( NetStatus != NERR_Success ) {
  1093. BrPrint(( BR_CRITICAL,
  1094. "%ws: Unbind failed on transport: %ws %ld\n",
  1095. DomainInfo->DomUnicodeDomainName,
  1096. Transport,
  1097. NetStatus ));
  1098. // ?? Anything else to do on failure
  1099. }
  1100. BrDereferenceNetwork( Network );
  1101. }
  1102. //
  1103. // Finish process the emulated domains
  1104. // Start at the front of the list since we dropped the lock.
  1105. //
  1106. BrDereferenceDomain(DomainInfo);
  1107. EnterCriticalSection(&NetworkCritSect);
  1108. DomainEntry = ServicedDomains.Flink;
  1109. }
  1110. LeaveCriticalSection(&NetworkCritSect);
  1111. break;
  1112. //
  1113. // Handle domain rename
  1114. //
  1115. case NlPnpDomainRename:
  1116. BrPrint(( BR_NETWORK,
  1117. "Received Domain Rename PNP for domain: %ws\n", HostedDomain ));
  1118. //
  1119. // See if we're handling the specified domain.
  1120. //
  1121. DomainInfo = BrFindDomain( HostedDomain, FALSE );
  1122. if ( DomainInfo == NULL ) {
  1123. BrPrint(( BR_CRITICAL, "%ws: Renamed domain doesn't exist\n",
  1124. HostedDomain ));
  1125. } else {
  1126. //
  1127. // If so,
  1128. // rename it.
  1129. //
  1130. BrRenameDomain( DomainInfo );
  1131. BrDereferenceDomain( DomainInfo );
  1132. }
  1133. break;
  1134. //
  1135. // Handle PDC/BDC role change.
  1136. //
  1137. case NlPnpNewRole:
  1138. BrPrint(( BR_NETWORK,
  1139. "%ws: Received role change PNP opcode 0x%lx on transport: %ws\n",
  1140. HostedDomain,
  1141. TransportFlags,
  1142. Transport ));
  1143. //
  1144. // Role can only change on lanman NT systems
  1145. //
  1146. if (!BrInfo.IsLanmanNt) {
  1147. break;
  1148. }
  1149. //
  1150. // See if we're handling the specified domain.
  1151. //
  1152. DomainInfo = BrFindDomain( HostedDomain, FALSE );
  1153. if ( DomainInfo == NULL ) {
  1154. BrPrint(( BR_CRITICAL, "%ws: Hosted domain doesn't exist\n",
  1155. HostedDomain ));
  1156. } else {
  1157. //
  1158. // Find the specified network
  1159. //
  1160. Network = BrFindNetwork( DomainInfo, &TransportName );
  1161. if ( Network == NULL ) {
  1162. BrPrint(( BR_CRITICAL,
  1163. "%ws: Unbind cannot find transport: %ws\n",
  1164. DomainInfo->DomUnicodeDomainName,
  1165. Transport ));
  1166. } else {
  1167. if (LOCK_NETWORK(Network)) {
  1168. //
  1169. // Set the role to be PDC.
  1170. //
  1171. if ( TransportFlags & LMDR_TRANSPORT_PDC ) {
  1172. //
  1173. // If we think we're a BDC. Update our information.
  1174. //
  1175. if ( (Network->Flags & NETWORK_PDC) == 0 ) {
  1176. Network->Flags |= NETWORK_PDC;
  1177. //
  1178. // Make sure a GetMasterAnnouncement request is pending.
  1179. //
  1180. (VOID) PostGetMasterAnnouncement ( Network );
  1181. // Force an election to let the PDC win
  1182. (VOID) BrElectMasterOnNet( Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_ROLE_CHANGED );
  1183. }
  1184. //
  1185. // Set the role to BDC.
  1186. //
  1187. } else {
  1188. //
  1189. // We think we're the PDC. Update our information.
  1190. //
  1191. if ( Network->Flags & NETWORK_PDC ) {
  1192. Network->Flags &= ~NETWORK_PDC;
  1193. // Force an election to let the PDC win
  1194. (VOID) BrElectMasterOnNet( Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_ROLE_CHANGED );
  1195. }
  1196. }
  1197. UNLOCK_NETWORK(Network);
  1198. }
  1199. BrDereferenceNetwork( Network );
  1200. }
  1201. BrDereferenceDomain( DomainInfo );
  1202. }
  1203. break;
  1204. //
  1205. // Ignore new Ip Addresses
  1206. //
  1207. case NlPnpNewIpAddress:
  1208. BrPrint(( BR_NETWORK,
  1209. "Received IP address change PNP opcode 0x%lx on transport: %ws\n",
  1210. TransportFlags,
  1211. Transport ));
  1212. break;
  1213. default:
  1214. BrPrint(( BR_CRITICAL,
  1215. "Received invalid PNP opcode 0x%x on transport: %ws\n",
  1216. PnpOpcode,
  1217. Transport ));
  1218. break;
  1219. }
  1220. try_exit:NOTHING;
  1221. } finally {
  1222. MIDL_user_free(Context);
  1223. //
  1224. // Always finish by asking for another PNP message.
  1225. //
  1226. // For PNP, it is fine to only process a single PNP message at a time.
  1227. // If this message mechanism starts being used for other purposes,
  1228. // we may want to immediately ask for another message upon receipt
  1229. // of this one.
  1230. //
  1231. while ((NetStatus = PostWaitForPnp()) != NERR_Success ) {
  1232. BrPrint(( BR_CRITICAL,
  1233. "Unable to re-issue PostWaitForPnp request (waiting): %ld\n",
  1234. NetStatus));
  1235. //
  1236. // On error, wait a second before returning. This ensures we don't
  1237. // consume the system in an infinite loop. We don't shutdown
  1238. // because the error might be a temporary low memory condition.
  1239. //
  1240. NetStatus = WaitForSingleObject( BrGlobalData.TerminateNowEvent, 1000 );
  1241. if ( NetStatus != WAIT_TIMEOUT ) {
  1242. BrPrint(( BR_CRITICAL,
  1243. "Not re-issuing PostWaitForPnp request since we're terminating: %ld\n",
  1244. NetStatus));
  1245. break;
  1246. }
  1247. }
  1248. }
  1249. return;
  1250. }
  1251. NET_API_STATUS
  1252. PostWaitForPnp (
  1253. VOID
  1254. )
  1255. /*++
  1256. Routine Description:
  1257. This function issues and async call to the bowser driver asking
  1258. it to inform us of PNP events.
  1259. Arguments:
  1260. None.
  1261. Return Value:
  1262. Status - The status of the operation.
  1263. --*/
  1264. {
  1265. return BrIssueAsyncBrowserIoControl(
  1266. NULL,
  1267. IOCTL_LMDR_BROWSER_PNP_READ,
  1268. HandlePnpMessage,
  1269. NULL );
  1270. }