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.

4190 lines
112 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. bowtdi.c
  5. Abstract:
  6. This module implements all of the routines that interface with the TDI
  7. transport for NT
  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. #include <isnkrnl.h>
  16. #include <smbipx.h>
  17. #include <nbtioctl.h>
  18. #pragma hdrstop
  19. typedef struct _ENUM_TRANSPORTS_CONTEXT {
  20. PVOID OutputBuffer;
  21. PVOID OutputBufferEnd;
  22. PVOID LastOutputBuffer; // Points to the last entry in the list.
  23. ULONG OutputBufferSize;
  24. ULONG EntriesRead;
  25. ULONG TotalEntries;
  26. ULONG TotalBytesNeeded;
  27. ULONG_PTR OutputBufferDisplacement;
  28. } ENUM_TRANSPORTS_CONTEXT, *PENUM_TRANSPORTS_CONTEXT;
  29. NTSTATUS
  30. EnumerateTransportsWorker(
  31. IN PTRANSPORT Transport,
  32. IN OUT PVOID Ctx
  33. );
  34. VOID
  35. BowserFreeBrowserServerList (
  36. IN PWSTR *BrowserServerList,
  37. IN ULONG BrowserServerListLength
  38. );
  39. ERESOURCE
  40. BowserTransportDatabaseResource = {0};
  41. //
  42. // Code for tracking missing frees.
  43. //
  44. #define BR_ONE_D_STACK_SIZE 5
  45. typedef struct _BrOneD {
  46. ULONG NameAdded;
  47. ULONG NameFreed;
  48. ULONG NameAddFailed;
  49. ULONG NameFreeFailed;
  50. ULONG NameAddStack[BR_ONE_D_STACK_SIZE];
  51. ULONG NameFreeStack[BR_ONE_D_STACK_SIZE];
  52. } BR_ONE_D;
  53. BR_ONE_D BrOneD;
  54. //
  55. //
  56. // Forward definitions of local routines.
  57. //
  58. NTSTATUS
  59. BowserpTdiSetEventHandler (
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PFILE_OBJECT FileObject,
  62. IN ULONG EventType,
  63. IN PVOID EventHandler,
  64. IN PVOID TransportName
  65. );
  66. NTSTATUS
  67. BowserDetermineProviderInformation(
  68. IN PUNICODE_STRING TransportName,
  69. OUT PTDI_PROVIDER_INFO ProviderInfo,
  70. OUT PULONG IpSubnetNumber
  71. );
  72. NTSTATUS
  73. UnbindTransportWorker(
  74. IN PTRANSPORT Transport,
  75. IN OUT PVOID Ctx
  76. );
  77. NTSTATUS
  78. BowserpTdiRemoveAddresses(
  79. IN PTRANSPORT Transport
  80. );
  81. VOID
  82. BowserDeleteTransport(
  83. IN PTRANSPORT Transport
  84. );
  85. VOID
  86. BowserpFreeTransport(
  87. IN PTRANSPORT Transport
  88. );
  89. NTSTATUS
  90. BowserSubmitTdiRequest (
  91. IN PFILE_OBJECT FileObject,
  92. IN PIRP Irp
  93. );
  94. NTSTATUS
  95. BowserCompleteTdiRequest (
  96. IN PDEVICE_OBJECT DeviceObject,
  97. IN PIRP Irp,
  98. IN PVOID Context
  99. );
  100. NTSTATUS
  101. CompleteSendDatagram (
  102. IN PDEVICE_OBJECT DeviceObject,
  103. IN PIRP Irp,
  104. IN PVOID Ctx
  105. );
  106. NTSTATUS
  107. BowserEnableIpxDatagramSocket(
  108. IN PTRANSPORT Transport
  109. );
  110. NTSTATUS
  111. BowserOpenNetbiosAddress(
  112. IN PPAGED_TRANSPORT_NAME PagedTransportName,
  113. IN PTRANSPORT Transport,
  114. IN PBOWSER_NAME Name
  115. );
  116. VOID
  117. BowserCloseNetbiosAddress(
  118. IN PTRANSPORT_NAME TransportName
  119. );
  120. VOID
  121. BowserCloseAllNetbiosAddresses(
  122. IN PTRANSPORT Transport
  123. );
  124. NTSTATUS
  125. BowserSendDatagram (
  126. IN PTRANSPORT Transport,
  127. IN PVOID RecipientAddress,
  128. IN DGRECEIVER_NAME_TYPE NameType,
  129. IN PVOID Buffer,
  130. IN ULONG BufferLength,
  131. IN BOOLEAN WaitForCompletion,
  132. IN PSTRING DestinationAddress OPTIONAL,
  133. IN BOOLEAN IsHostAnnouncment
  134. );
  135. NTSTATUS
  136. OpenIpxSocket (
  137. OUT PHANDLE Handle,
  138. OUT PFILE_OBJECT *FileObject,
  139. OUT PDEVICE_OBJECT *DeviceObject,
  140. IN PUNICODE_STRING DeviceName,
  141. IN USHORT Socket
  142. );
  143. NTSTATUS
  144. BowserIssueTdiAction (
  145. IN PDEVICE_OBJECT DeviceObject,
  146. IN PFILE_OBJECT FileObject,
  147. IN PVOID Action,
  148. IN ULONG ActionSize
  149. );
  150. NTSTATUS
  151. GetNetworkAddress (
  152. IN PTRANSPORT_NAME TransportName
  153. );
  154. #ifdef ALLOC_PRAGMA
  155. #pragma alloc_text(PAGE, BowserTdiAllocateTransport)
  156. #pragma alloc_text(PAGE, BowserUnbindFromAllTransports)
  157. #pragma alloc_text(PAGE, UnbindTransportWorker)
  158. #pragma alloc_text(PAGE, BowserFreeTransportByName)
  159. #pragma alloc_text(PAGE, BowserTransportFlags)
  160. #pragma alloc_text(PAGE, BowserEnumerateTransports)
  161. #pragma alloc_text(PAGE, EnumerateTransportsWorker)
  162. #pragma alloc_text(PAGE, BowserDereferenceTransport)
  163. #pragma alloc_text(PAGE, BowserCreateTransportName)
  164. #pragma alloc_text(PAGE, BowserpTdiRemoveAddresses)
  165. #pragma alloc_text(PAGE, BowserFindTransportName)
  166. #pragma alloc_text(PAGE, BowserFreeTransportName)
  167. #pragma alloc_text(PAGE, BowserDeleteTransport)
  168. #pragma alloc_text(PAGE, BowserpFreeTransport)
  169. #pragma alloc_text(PAGE, BowserpTdiSetEventHandler)
  170. #pragma alloc_text(PAGE, BowserBuildTransportAddress)
  171. #pragma alloc_text(PAGE, BowserUpdateProviderInformation)
  172. #pragma alloc_text(PAGE, BowserDetermineProviderInformation)
  173. #pragma alloc_text(PAGE, BowserFindTransport)
  174. #pragma alloc_text(PAGE, BowserForEachTransport)
  175. #pragma alloc_text(PAGE, BowserForEachTransportName)
  176. #pragma alloc_text(PAGE, BowserDeleteTransportNameByName)
  177. #pragma alloc_text(PAGE, BowserSubmitTdiRequest)
  178. #pragma alloc_text(PAGE, BowserSendDatagram)
  179. #pragma alloc_text(PAGE, BowserSendSecondClassMailslot)
  180. #pragma alloc_text(PAGE, BowserSendRequestAnnouncement)
  181. #pragma alloc_text(INIT, BowserpInitializeTdi)
  182. #pragma alloc_text(PAGE, BowserpUninitializeTdi)
  183. #pragma alloc_text(PAGE, BowserDereferenceTransportName)
  184. #pragma alloc_text(PAGE, BowserEnableIpxDatagramSocket)
  185. #pragma alloc_text(PAGE, BowserOpenNetbiosAddress)
  186. #pragma alloc_text(PAGE, BowserCloseNetbiosAddress)
  187. #pragma alloc_text(PAGE, BowserCloseAllNetbiosAddresses)
  188. #pragma alloc_text(PAGE, OpenIpxSocket)
  189. #pragma alloc_text(PAGE, BowserIssueTdiAction)
  190. #pragma alloc_text(PAGE4BROW, BowserCompleteTdiRequest)
  191. #pragma alloc_text(PAGE4BROW, CompleteSendDatagram)
  192. #endif
  193. //
  194. // Flag to indicate that a network isn't an IP network
  195. //
  196. #define BOWSER_NON_IP_SUBNET 0xFFFFFFFF
  197. NTSTATUS
  198. BowserTdiAllocateTransport (
  199. PUNICODE_STRING TransportName,
  200. PUNICODE_STRING EmulatedDomainName,
  201. PUNICODE_STRING EmulatedComputerName
  202. )
  203. /*++
  204. Routine Description:
  205. This routine will allocate a transport descriptor and bind the bowser
  206. to the transport.
  207. Arguments:
  208. TransportName - Supplies the name of the transport provider
  209. EmulatedDomainName - Supplies the name of the domain being emulated
  210. EmulatedComputerName - Supplies the name of the computer in the emulated domain.
  211. Return Value:
  212. NTSTATUS - Status of operation.
  213. --*/
  214. {
  215. NTSTATUS Status;
  216. PTRANSPORT NewTransport;
  217. BOOLEAN ResourceAcquired = FALSE;
  218. PAGED_CODE();
  219. // DbgBreakPoint();
  220. dlog(DPRT_TDI, ("%wZ: %wZ: BowserTdiAllocateTransport\n", EmulatedDomainName, TransportName));
  221. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  222. ResourceAcquired = TRUE;
  223. NewTransport = BowserFindTransport(TransportName, EmulatedDomainName );
  224. dprintf(DPRT_REF, ("Called Find transport %lx from BowserTdiAllocateTransport.\n", NewTransport));
  225. if (NewTransport == NULL) {
  226. PLIST_ENTRY NameEntry;
  227. PPAGED_TRANSPORT PagedTransport = NULL;
  228. PCHAR Where;
  229. ULONG PagedTransportSize;
  230. //
  231. // Allocate and initialize the constant parts of the transport structure.
  232. //
  233. NewTransport = ALLOCATE_POOL(NonPagedPool, sizeof(TRANSPORT), POOL_TRANSPORT);
  234. if (NewTransport == NULL) {
  235. Status = STATUS_INSUFFICIENT_RESOURCES;
  236. goto ReturnStatus;
  237. }
  238. RtlZeroMemory( NewTransport, sizeof(TRANSPORT) );
  239. NewTransport->Signature = STRUCTURE_SIGNATURE_TRANSPORT;
  240. NewTransport->Size = sizeof(TRANSPORT);
  241. //
  242. // One reference for the rest of this procedure.
  243. //
  244. // We increment it later when we insert it in the global list.
  245. //
  246. NewTransport->ReferenceCount = 1;
  247. ExInitializeResourceLite(&NewTransport->BrowserServerListResource);
  248. KeInitializeEvent(&NewTransport->GetBackupListComplete, NotificationEvent, TRUE);
  249. ExInitializeResourceLite(&NewTransport->Lock);
  250. BowserInitializeIrpQueue(&NewTransport->BecomeBackupQueue);
  251. BowserInitializeIrpQueue(&NewTransport->BecomeMasterQueue);
  252. BowserInitializeIrpQueue(&NewTransport->FindMasterQueue);
  253. BowserInitializeIrpQueue(&NewTransport->WaitForMasterAnnounceQueue);
  254. BowserInitializeIrpQueue(&NewTransport->WaitForNewMasterNameQueue);
  255. BowserInitializeIrpQueue(&NewTransport->ChangeRoleQueue);
  256. BowserInitializeTimer(&NewTransport->ElectionTimer);
  257. BowserInitializeTimer(&NewTransport->FindMasterTimer);
  258. INITIALIZE_ANNOUNCE_DATABASE(NewTransport);
  259. //
  260. // Allocate and initialize the constant parts of the paged transport structure.
  261. //
  262. PagedTransportSize =sizeof(PAGED_TRANSPORT) +
  263. max(sizeof(TA_IPX_ADDRESS), sizeof(TA_NETBIOS_ADDRESS)) +
  264. sizeof(WCHAR) + // alignment
  265. (LM20_CNLEN+1)*sizeof(WCHAR) +
  266. TransportName->Length + sizeof(WCHAR);
  267. PagedTransport = NewTransport->PagedTransport =
  268. ALLOCATE_POOL(PagedPool, PagedTransportSize, POOL_PAGED_TRANSPORT);
  269. if (PagedTransport == NULL) {
  270. Status = STATUS_INSUFFICIENT_RESOURCES;
  271. goto ReturnStatus;
  272. }
  273. RtlZeroMemory( PagedTransport, PagedTransportSize );
  274. PagedTransport->NonPagedTransport = NewTransport;
  275. PagedTransport->Signature = STRUCTURE_SIGNATURE_PAGED_TRANSPORT;
  276. PagedTransport->Size = sizeof(PAGED_TRANSPORT);
  277. InitializeListHead(&PagedTransport->GlobalNext);
  278. InitializeListHead(&PagedTransport->NameChain);
  279. PagedTransport->Role = None;
  280. PagedTransport->IpSubnetNumber = BOWSER_NON_IP_SUBNET;
  281. PagedTransport->DisabledTransport = TRUE;
  282. PagedTransport->PointToPoint = FALSE;
  283. RtlInitializeGenericTable(&PagedTransport->AnnouncementTable,
  284. BowserCompareAnnouncement,
  285. BowserAllocateAnnouncement,
  286. BowserFreeAnnouncement,
  287. NULL);
  288. RtlInitializeGenericTable(&PagedTransport->DomainTable,
  289. BowserCompareAnnouncement,
  290. BowserAllocateAnnouncement,
  291. BowserFreeAnnouncement,
  292. NULL);
  293. InitializeListHead(&PagedTransport->BackupBrowserList);
  294. PagedTransport->NumberOfBackupServerListEntries = 0;
  295. // Put the MasterBrowserAddress at the end of the allocated buffer
  296. Where = (PCHAR)(PagedTransport+1);
  297. PagedTransport->MasterBrowserAddress.Buffer = Where;
  298. PagedTransport->MasterBrowserAddress.MaximumLength = max(sizeof(TA_IPX_ADDRESS),
  299. sizeof(TA_NETBIOS_ADDRESS));
  300. Where += PagedTransport->MasterBrowserAddress.MaximumLength;
  301. // Put the MasterName at the end of the allocated buffer
  302. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  303. PagedTransport->MasterName.Buffer = (LPWSTR) Where;
  304. PagedTransport->MasterName.MaximumLength = (LM20_CNLEN+1)*sizeof(WCHAR);
  305. Where += PagedTransport->MasterName.MaximumLength;
  306. // Put the TransportName at the end of the allocated buffer
  307. PagedTransport->TransportName.Buffer = (LPWSTR) Where;
  308. PagedTransport->TransportName.MaximumLength = TransportName->Length + sizeof(WCHAR);
  309. RtlCopyUnicodeString(&PagedTransport->TransportName, TransportName);
  310. Where += PagedTransport->TransportName.MaximumLength;
  311. //
  312. // Make this transport a part of a domain.
  313. //
  314. NewTransport->DomainInfo = BowserCreateDomain( EmulatedDomainName, EmulatedComputerName );
  315. if ( NewTransport->DomainInfo == NULL ) {
  316. Status = STATUS_INSUFFICIENT_RESOURCES;
  317. goto ReturnStatus;
  318. }
  319. //
  320. // Get info from the provider
  321. // (e.g., RAS, Wannish, DatagramSize)
  322. Status= BowserUpdateProviderInformation( PagedTransport );
  323. if (!NT_SUCCESS(Status)) {
  324. goto ReturnStatus;
  325. }
  326. PagedTransport->Flags = 0;
  327. //
  328. // We ignore any and all errors that occur when we open the IPX socket.
  329. //
  330. //
  331. // Open the IPX mailslot socket.
  332. //
  333. Status = OpenIpxSocket(
  334. &PagedTransport->IpxSocketHandle,
  335. &NewTransport->IpxSocketFileObject,
  336. &NewTransport->IpxSocketDeviceObject,
  337. &PagedTransport->TransportName,
  338. SMB_IPX_MAILSLOT_SOCKET
  339. );
  340. if ( NT_SUCCESS(Status) ) {
  341. PagedTransport->Flags |= DIRECT_HOST_IPX;
  342. // We'll use type 20 packets to increase the reach of broadcasts
  343. // so don't treat this as a wannish protocol.
  344. PagedTransport->Wannish = FALSE;
  345. }
  346. //
  347. // Create the names for this transport.
  348. // (Only if the caller asked us to)
  349. //
  350. // Being in the global list constitutes a reference.
  351. //
  352. InsertTailList(&BowserTransportHead, &PagedTransport->GlobalNext);
  353. BowserReferenceTransport( NewTransport );
  354. //
  355. // The names are added asynchronously in other threads that require this
  356. // resource.
  357. //
  358. if ( ResourceAcquired ) {
  359. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  360. ResourceAcquired = FALSE;
  361. }
  362. Status = BowserAddDefaultNames( NewTransport, NULL );
  363. if ( !NT_SUCCESS(Status) ) {
  364. goto ReturnStatus;
  365. }
  366. //
  367. // Start receiving broadcasts on IPX now that the names exist.
  368. //
  369. if ( PagedTransport->Flags & DIRECT_HOST_IPX ) {
  370. //
  371. // Acquire the lock while referencing IpxSocket*
  372. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  373. ResourceAcquired = TRUE;
  374. BowserEnableIpxDatagramSocket(NewTransport);
  375. }
  376. //
  377. // Notify services that this transport is now bound
  378. //
  379. BowserSendPnp( NlPnpTransportBind,
  380. NULL, // All hosted domains
  381. &PagedTransport->TransportName,
  382. BowserTransportFlags(PagedTransport) );
  383. }
  384. Status = STATUS_SUCCESS;
  385. ReturnStatus:
  386. if ( ResourceAcquired ) {
  387. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  388. }
  389. if (!NT_SUCCESS(Status)) {
  390. //
  391. // Delete the transport.
  392. //
  393. if ( NewTransport != NULL ) {
  394. // Remove the global reference if in global list
  395. BowserDeleteTransport (NewTransport);
  396. }
  397. }
  398. // Remove the local reference
  399. if ( NewTransport != NULL ) {
  400. BowserDereferenceTransport( NewTransport );
  401. }
  402. return Status;
  403. }
  404. NTSTATUS
  405. BowserUnbindFromAllTransports(
  406. VOID
  407. )
  408. {
  409. NTSTATUS Status;
  410. PAGED_CODE();
  411. Status = BowserForEachTransport(UnbindTransportWorker, NULL);
  412. #if DBG
  413. if (NT_SUCCESS(Status)) {
  414. ASSERT (IsListEmpty(&BowserTransportHead));
  415. }
  416. #endif
  417. return Status;
  418. }
  419. NTSTATUS
  420. UnbindTransportWorker(
  421. IN PTRANSPORT Transport,
  422. IN OUT PVOID Ctx
  423. )
  424. /*++
  425. Routine Description:
  426. This routine is the worker routine for BowserUnbindFromAllTransports.
  427. Arguments:
  428. None.
  429. Return Value:
  430. None.
  431. --*/
  432. {
  433. PAGED_CODE();
  434. //
  435. // Dereference the reference caused by the transport bind.
  436. //
  437. BowserDeleteTransport(Transport);
  438. //
  439. // Return success. We're done.
  440. //
  441. return(STATUS_SUCCESS);
  442. UNREFERENCED_PARAMETER(Ctx);
  443. }
  444. NTSTATUS
  445. BowserFreeTransportByName (
  446. IN PUNICODE_STRING TransportName,
  447. IN PUNICODE_STRING EmulatedDomainName
  448. )
  449. /*++
  450. Routine Description:
  451. This routine will deallocate an allocated transport
  452. Arguments:
  453. TransportName - Supplies a pointer to the name of the transport to free
  454. EmulatedDomainName - Name of the emulated domain whose transport is to be freed
  455. Return Value:
  456. None.
  457. --*/
  458. {
  459. PTRANSPORT Transport;
  460. PAGED_CODE();
  461. dlog(DPRT_TDI, ("%wZ: %wZ: BowserFreeTransportByName: Remove transport\n", EmulatedDomainName, TransportName));
  462. Transport = BowserFindTransport(TransportName, EmulatedDomainName );
  463. dprintf(DPRT_REF, ("Called Find transport %lx from BowserFreeTransportByName.\n", Transport));
  464. if (Transport == NULL) {
  465. return STATUS_OBJECT_NAME_NOT_FOUND;
  466. }
  467. //
  468. // Remove the reference from the binding.
  469. //
  470. BowserDeleteTransport(Transport);
  471. //
  472. // Remove the reference from the FindTransport.
  473. //
  474. BowserDereferenceTransport(Transport);
  475. return STATUS_SUCCESS;
  476. }
  477. NTSTATUS
  478. BowserEnumerateTransports (
  479. OUT PVOID OutputBuffer,
  480. OUT ULONG OutputBufferLength,
  481. IN OUT PULONG EntriesRead,
  482. IN OUT PULONG TotalEntries,
  483. IN OUT PULONG TotalBytesNeeded,
  484. IN ULONG_PTR OutputBufferDisplacement)
  485. /*++
  486. Routine Description:
  487. This routine will enumerate the servers in the bowsers current announcement
  488. table.
  489. Arguments:
  490. IN ULONG ServerTypeMask - Mask of servers to return.
  491. IN PUNICODE_STRING DomainName OPTIONAL - Domain to filter (all if not specified)
  492. OUT PVOID OutputBuffer - Buffer to fill with server info.
  493. IN ULONG OutputBufferSize - Filled in with size of buffer.
  494. OUT PULONG EntriesRead - Filled in with the # of entries returned.
  495. OUT PULONG TotalEntries - Filled in with the total # of entries.
  496. OUT PULONG TotalBytesNeeded - Filled in with the # of bytes needed.
  497. Return Value:
  498. None.
  499. --*/
  500. {
  501. PVOID OutputBufferEnd;
  502. NTSTATUS Status;
  503. ENUM_TRANSPORTS_CONTEXT Context;
  504. PDOMAIN_INFO DomainInfo = NULL;
  505. PAGED_CODE();
  506. OutputBufferEnd = (PCHAR)OutputBuffer+OutputBufferLength;
  507. Context.EntriesRead = 0;
  508. Context.TotalEntries = 0;
  509. Context.TotalBytesNeeded = 0;
  510. try {
  511. Context.OutputBufferSize = OutputBufferLength;
  512. Context.OutputBuffer = OutputBuffer;
  513. Context.OutputBufferDisplacement = OutputBufferDisplacement;
  514. Context.OutputBufferEnd = OutputBufferEnd;
  515. Context.LastOutputBuffer = OutputBuffer;
  516. dlog(DPRT_FSCTL, ("Enumerate Transports: Buffer: %lx, BufferSize: %lx, BufferEnd: %lx\n",
  517. OutputBuffer, OutputBufferLength, OutputBufferEnd));
  518. try {
  519. //
  520. // Find the primary domain.
  521. //
  522. // This call is intended to return the actual transport names and not the
  523. // network structure which are duplicated for each emulated domain.
  524. //
  525. DomainInfo = BowserFindDomain( NULL );
  526. // Failure case handled below
  527. //
  528. // Enumerate the transports.
  529. //
  530. if ( DomainInfo != NULL ) {
  531. Status = BowserForEachTransportInDomain( DomainInfo, EnumerateTransportsWorker, &Context);
  532. }
  533. *EntriesRead = Context.EntriesRead;
  534. *TotalEntries = Context.TotalEntries;
  535. *TotalBytesNeeded = Context.TotalBytesNeeded;
  536. if (*EntriesRead != 0) {
  537. ((PLMDR_TRANSPORT_LIST )Context.LastOutputBuffer)->NextEntryOffset = 0;
  538. }
  539. dlog(DPRT_FSCTL, ("TotalEntries: %lx EntriesRead: %lx, TotalBytesNeeded: %lx\n", *TotalEntries, *EntriesRead, *TotalBytesNeeded));
  540. if (*EntriesRead == *TotalEntries) {
  541. try_return(Status = STATUS_SUCCESS);
  542. } else {
  543. try_return(Status = STATUS_MORE_ENTRIES);
  544. }
  545. try_exit:NOTHING;
  546. } finally {
  547. if ( DomainInfo != NULL ) {
  548. BowserDereferenceDomain( DomainInfo );
  549. }
  550. }
  551. }
  552. except ( BR_EXCEPTION ) {
  553. Status = GetExceptionCode();
  554. }
  555. return Status;
  556. }
  557. ULONG
  558. BowserTransportFlags(
  559. IN PPAGED_TRANSPORT PagedTransport
  560. )
  561. /*++
  562. Routine Description:
  563. Return the user mode transport flags for this transport.
  564. Arguments:
  565. PageTransport - Transport to return the flags for.
  566. Return Value:
  567. The appropriate of the following flags:
  568. LMDR_TRANSPORT_WANNISH
  569. LMDR_TRANSPORT_RAS
  570. LMDR_TRANSPORT_IPX
  571. --*/
  572. {
  573. ULONG TransportFlags = 0;
  574. PAGED_CODE();
  575. if (PagedTransport->Wannish) {
  576. TransportFlags |= LMDR_TRANSPORT_WANNISH;
  577. }
  578. if (PagedTransport->IsPrimaryDomainController) {
  579. TransportFlags |= LMDR_TRANSPORT_PDC;
  580. }
  581. if (PagedTransport->PointToPoint) {
  582. TransportFlags |= LMDR_TRANSPORT_RAS;
  583. }
  584. if (PagedTransport->Flags & DIRECT_HOST_IPX) {
  585. TransportFlags |= LMDR_TRANSPORT_IPX;
  586. }
  587. return TransportFlags;
  588. }
  589. NTSTATUS
  590. EnumerateTransportsWorker(
  591. IN PTRANSPORT Transport,
  592. IN OUT PVOID Ctx
  593. )
  594. /*++
  595. Routine Description:
  596. This routine is the worker routine for BowserEnumerateTransports.
  597. It is called for each of the serviced transports in the bowser and
  598. returns the size needed to enumerate the servers received on each transport.
  599. Arguments:
  600. None.
  601. Return Value:
  602. None.
  603. --*/
  604. {
  605. PENUM_TRANSPORTS_CONTEXT Context = Ctx;
  606. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  607. ULONG SizeNeeded = sizeof(LMDR_TRANSPORT_LIST);
  608. PAGED_CODE();
  609. SizeNeeded += PagedTransport->TransportName.Length+sizeof(WCHAR);
  610. SizeNeeded = ROUND_UP_COUNT(SizeNeeded,ALIGN_DWORD);
  611. Context->TotalEntries += 1;
  612. if ((ULONG_PTR)Context->OutputBufferEnd - (ULONG_PTR)Context->OutputBuffer > SizeNeeded) {
  613. PLMDR_TRANSPORT_LIST TransportEntry = (PLMDR_TRANSPORT_LIST)Context->OutputBuffer;
  614. Context->LastOutputBuffer = Context->OutputBuffer;
  615. Context->EntriesRead += 1;
  616. RtlCopyMemory(TransportEntry->TransportName, PagedTransport->TransportName.Buffer, PagedTransport->TransportName.Length+sizeof(WCHAR));
  617. //
  618. // Null terminate the transport name.
  619. //
  620. TransportEntry->TransportName[PagedTransport->TransportName.Length/sizeof(WCHAR)] = '\0';
  621. TransportEntry->TransportNameLength = PagedTransport->TransportName.Length;
  622. TransportEntry->Flags |= BowserTransportFlags( PagedTransport );
  623. TransportEntry->NextEntryOffset = SizeNeeded;
  624. (PUCHAR)(Context->OutputBuffer) += SizeNeeded;
  625. }
  626. Context->TotalBytesNeeded += SizeNeeded;
  627. return(STATUS_SUCCESS);
  628. }
  629. VOID
  630. BowserReferenceTransport(
  631. IN PTRANSPORT Transport
  632. )
  633. {
  634. InterlockedIncrement(&Transport->ReferenceCount);
  635. dprintf(DPRT_REF, ("Reference transport %lx. Count now %lx\n", Transport, Transport->ReferenceCount));
  636. }
  637. VOID
  638. BowserDereferenceTransport(
  639. IN PTRANSPORT Transport
  640. )
  641. {
  642. LONG Result;
  643. PAGED_CODE();
  644. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  645. if (Transport->ReferenceCount == 0) {
  646. InternalError(("Transport Reference Count mismatch\n"));
  647. }
  648. Result = InterlockedDecrement(&Transport->ReferenceCount);
  649. dlog(DPRT_REF, ("Dereference transport %lx. Count now %lx\n", Transport, Transport->ReferenceCount));
  650. if (Result == 0) {
  651. //
  652. // And free up the transport itself.
  653. //
  654. BowserpFreeTransport(Transport);
  655. }
  656. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  657. }
  658. NTSTATUS
  659. BowserCreateTransportName (
  660. IN PTRANSPORT Transport,
  661. IN PBOWSER_NAME Name
  662. )
  663. /*++
  664. Routine Description:
  665. This routine creates a transport address object.
  666. Arguments:
  667. IN PTRANSPORT Transport - Supplies a transport structure describing the
  668. transport address object to be created.
  669. Return Value:
  670. NTSTATUS - Status of resulting operation.
  671. --*/
  672. {
  673. NTSTATUS Status = STATUS_SUCCESS;
  674. PTRANSPORT_NAME TransportName = NULL;
  675. PPAGED_TRANSPORT_NAME PagedTransportName = NULL;
  676. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  677. BOOLEAN ResourceAcquired = FALSE;
  678. PAGED_CODE();
  679. ASSERT(Transport->Signature == STRUCTURE_SIGNATURE_TRANSPORT);
  680. dlog(DPRT_TDI,
  681. ("%s: %ws: BowserCreateTransportName. Name %wZ (%ld)\n",
  682. Transport->DomainInfo->DomOemDomainName,
  683. PagedTransport->TransportName.Buffer,
  684. &Name->Name,
  685. Name->NameType ));
  686. //
  687. // Link the transport_name structure into the transport list.
  688. //
  689. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  690. ResourceAcquired = TRUE;
  691. TransportName = BowserFindTransportName(Transport, Name);
  692. if (TransportName != NULL) {
  693. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  694. return(STATUS_SUCCESS);
  695. }
  696. #ifdef notdef
  697. //
  698. // Simply don't allocate certain names if the transport is disabled
  699. //
  700. if ( PagedTransport->DisabledTransport ) {
  701. if ( Name->NameType == PrimaryDomainBrowser ) {
  702. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  703. return STATUS_SUCCESS;
  704. }
  705. }
  706. #endif // notdef
  707. // s.b. assertion that we're attached to the system process
  708. // ASSERT (IoGetCurrentProcess() == BowserFspProcess);
  709. //
  710. // Allocate a structure to refer to this name on the transport
  711. //
  712. TransportName = ALLOCATE_POOL(NonPagedPool, sizeof(TRANSPORT_NAME) +
  713. max(sizeof(TA_NETBIOS_ADDRESS),
  714. sizeof(TA_IPX_ADDRESS)), POOL_TRANSPORTNAME);
  715. if (TransportName == NULL) {
  716. Status = STATUS_INSUFFICIENT_RESOURCES;
  717. goto error_cleanup;
  718. }
  719. TransportName->PagedTransportName = PagedTransportName =
  720. ALLOCATE_POOL(PagedPool,
  721. sizeof(PAGED_TRANSPORT_NAME),
  722. POOL_PAGED_TRANSPORTNAME);
  723. if (PagedTransportName == NULL) {
  724. FREE_POOL( TransportName );
  725. TransportName = NULL;
  726. Status = STATUS_INSUFFICIENT_RESOURCES;
  727. goto error_cleanup;
  728. }
  729. TransportName->Signature = STRUCTURE_SIGNATURE_TRANSPORTNAME;
  730. TransportName->Size = sizeof(TRANSPORT_NAME);
  731. TransportName->PagedTransportName = PagedTransportName;
  732. // This TransportName is considered to be referenced by the transport via
  733. // Transport->PagedTransport->NameChain. The Name->NameChain isn't
  734. // considered to be a reference.
  735. //
  736. // The second reference is a local reference for the lifetime of this routine.
  737. //
  738. TransportName->ReferenceCount = 2;
  739. PagedTransportName->NonPagedTransportName = TransportName;
  740. PagedTransportName->Signature = STRUCTURE_SIGNATURE_PAGED_TRANSPORTNAME;
  741. PagedTransportName->Size = sizeof(PAGED_TRANSPORT_NAME);
  742. PagedTransportName->Name = Name;
  743. BowserReferenceName(Name);
  744. TransportName->Transport = Transport;
  745. // Don't reference the Transport. When the transport is unbound, we'll
  746. // make sure all the transport names are removed first.
  747. // BowserReferenceTransport(Transport);
  748. PagedTransportName->Handle = NULL;
  749. TransportName->FileObject = NULL;
  750. TransportName->DeviceObject = NULL;
  751. InsertHeadList(&Transport->PagedTransport->NameChain, &PagedTransportName->TransportNext);
  752. InsertHeadList(&Name->NameChain, &PagedTransportName->NameNext);
  753. //
  754. // If this is an OTHERDOMAIN, we want to process host announcements for
  755. // the domain, if it isn't, we want to wait until we become a master.
  756. //
  757. if (Name->NameType == OtherDomain) {
  758. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  759. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  760. TransportName->ProcessHostAnnouncements = TRUE;
  761. } else {
  762. TransportName->ProcessHostAnnouncements = FALSE;
  763. }
  764. //
  765. // If this name is one of our special names, we want to remember it in
  766. // the transport block.
  767. //
  768. switch (Name->NameType) {
  769. case ComputerName:
  770. Transport->ComputerName = TransportName;
  771. break;
  772. case PrimaryDomain:
  773. //
  774. // During domain rename we can temporarily have two primary names assigned.
  775. // keep track of both names.
  776. //
  777. if ( Transport->PrimaryDomain != NULL ) {
  778. ASSERT( Transport->AltPrimaryDomain == NULL );
  779. Transport->AltPrimaryDomain = Transport->PrimaryDomain;
  780. }
  781. Transport->PrimaryDomain = TransportName;
  782. break;
  783. case MasterBrowser:
  784. Transport->MasterBrowser = TransportName;
  785. break;
  786. case BrowserElection:
  787. Transport->BrowserElection = TransportName;
  788. break;
  789. case PrimaryDomainBrowser:
  790. PagedTransport->IsPrimaryDomainController = TRUE;
  791. //
  792. // Notify services we are now a PDC.
  793. //
  794. BowserSendPnp(
  795. NlPnpNewRole,
  796. &Transport->DomainInfo->DomUnicodeDomainName,
  797. &Transport->PagedTransport->TransportName,
  798. BowserTransportFlags(Transport->PagedTransport) );
  799. break;
  800. }
  801. TransportName->TransportAddress.Buffer = (PCHAR)(TransportName+1);
  802. TransportName->TransportAddress.MaximumLength = max(sizeof(TA_NETBIOS_ADDRESS),
  803. sizeof(TA_IPX_ADDRESS));
  804. //
  805. // Figure out what this name is, so we can match against it when
  806. // a datagram is received.
  807. //
  808. Status = BowserBuildTransportAddress(&TransportName->TransportAddress, &Name->Name, Name->NameType, Transport);
  809. if (!NT_SUCCESS(Status)) {
  810. goto error_cleanup;
  811. }
  812. TransportName->NameType = (CHAR)Name->NameType;
  813. #if DBG
  814. if (Name->NameType == MasterBrowser) {
  815. //
  816. // make sure that we never become a master without locking the discardable code.
  817. //
  818. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  819. }
  820. #endif
  821. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  822. ResourceAcquired = FALSE;
  823. //
  824. // On non direct host IPX transports, we need to add the name now.
  825. //
  826. if (!FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
  827. Status = BowserOpenNetbiosAddress(PagedTransportName, Transport, Name);
  828. if (!NT_SUCCESS(Status)) {
  829. goto error_cleanup;
  830. }
  831. }
  832. error_cleanup:
  833. if ( !NT_SUCCESS(Status) ) {
  834. dlog(DPRT_TDI,
  835. ("%s: %ws: BowserCreateTransportName fail. Name %wZ (%ld) Status:%lx\n",
  836. Transport->DomainInfo->DomOemDomainName,
  837. PagedTransport->TransportName.Buffer,
  838. &Name->Name,
  839. Name->NameType,
  840. Status ));
  841. //
  842. // Remove Transport->PagedTransport->NameChain reference
  843. // (Unless another routine already has done that behind our back)
  844. //
  845. if (TransportName != NULL) {
  846. if ( PagedTransportName->TransportNext.Flink != NULL ) {
  847. BowserDereferenceTransportName(TransportName);
  848. }
  849. }
  850. }
  851. // Remove the local reference
  852. if (TransportName != NULL) {
  853. BowserDereferenceTransportName(TransportName);
  854. }
  855. if (ResourceAcquired) {
  856. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  857. }
  858. return Status;
  859. }
  860. NTSTATUS
  861. BowserOpenNetbiosAddress(
  862. IN PPAGED_TRANSPORT_NAME PagedTransportName,
  863. IN PTRANSPORT Transport,
  864. IN PBOWSER_NAME Name
  865. )
  866. {
  867. NTSTATUS Status;
  868. PFILE_FULL_EA_INFORMATION EABuffer = NULL;
  869. PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
  870. OBJECT_ATTRIBUTES AddressAttributes;
  871. IO_STATUS_BLOCK IoStatusBlock;
  872. HANDLE Handle = NULL;
  873. PFILE_OBJECT FileObject = NULL;
  874. PDEVICE_OBJECT DeviceObject;
  875. PAGED_CODE( );
  876. try {
  877. //
  878. // Now create the address object for this name.
  879. //
  880. EABuffer = ALLOCATE_POOL(PagedPool,
  881. sizeof(FILE_FULL_EA_INFORMATION)-1 +
  882. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  883. max(sizeof(TA_NETBIOS_EX_ADDRESS), sizeof(TA_NETBIOS_ADDRESS)),
  884. POOL_EABUFFER);
  885. if (EABuffer == NULL) {
  886. try_return(Status = STATUS_INSUFFICIENT_RESOURCES)
  887. }
  888. EABuffer->NextEntryOffset = 0;
  889. EABuffer->Flags = 0;
  890. EABuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  891. RtlCopyMemory(EABuffer->EaName, TdiTransportAddress, EABuffer->EaNameLength+1);
  892. EABuffer->EaValueLength = sizeof(TA_NETBIOS_ADDRESS);
  893. ASSERT (TransportName->TransportAddress.Length == sizeof(TA_NETBIOS_ADDRESS));
  894. RtlCopyMemory( &EABuffer->EaName[TDI_TRANSPORT_ADDRESS_LENGTH+1],
  895. TransportName->TransportAddress.Buffer,
  896. EABuffer->EaValueLength );
  897. dlog(DPRT_TDI,
  898. ("%s: %ws: Create endpoint of %wZ (%ld) @(%lx)\n",
  899. Transport->DomainInfo->DomOemDomainName,
  900. Transport->PagedTransport->TransportName.Buffer,
  901. &PagedTransportName->Name->Name,
  902. PagedTransportName->Name->NameType,
  903. TransportName));
  904. InitializeObjectAttributes (&AddressAttributes,
  905. &Transport->PagedTransport->TransportName, // Name
  906. OBJ_CASE_INSENSITIVE,// Attributes
  907. NULL, // RootDirectory
  908. NULL); // SecurityDescriptor
  909. Status = IoCreateFile( &Handle, // Handle
  910. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  911. &AddressAttributes, // Object Attributes
  912. &IoStatusBlock, // Final I/O status block
  913. NULL, // Allocation Size
  914. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  915. FILE_SHARE_READ,// Sharing attributes
  916. FILE_OPEN_IF, // Create disposition
  917. 0, // CreateOptions
  918. EABuffer, // EA Buffer
  919. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
  920. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  921. sizeof(TA_NETBIOS_ADDRESS), // EA length
  922. CreateFileTypeNone,
  923. NULL,
  924. IO_NO_PARAMETER_CHECKING | // All of the buffers are kernel buffers
  925. IO_CHECK_CREATE_PARAMETERS);// But double check parameter consistancy
  926. FREE_POOL(EABuffer);
  927. EABuffer = NULL;
  928. if (!NT_SUCCESS(Status)) {
  929. try_return(Status);
  930. }
  931. if (!NT_SUCCESS(Status = IoStatusBlock.Status)) {
  932. try_return(Status);
  933. }
  934. //
  935. // Obtain a referenced pointer to the file object.
  936. //
  937. Status = ObReferenceObjectByHandle (
  938. Handle,
  939. 0,
  940. *IoFileObjectType,
  941. KernelMode,
  942. (PVOID *)&FileObject,
  943. NULL
  944. );
  945. if (!NT_SUCCESS(Status)) {
  946. try_return(Status);
  947. }
  948. //
  949. // Get another reference that lasts for the life of the TransportName
  950. //
  951. ObReferenceObject( FileObject );
  952. //
  953. // Get the address of the device object for the endpoint.
  954. //
  955. DeviceObject = IoGetRelatedDeviceObject( FileObject );
  956. //
  957. // Note: due to bug 140751 we'll first set nbt's handler
  958. // to get it going & only then we would asign the handles
  959. // to the global structure. This is in order to prevent
  960. // execution of BowserCloseNetbiosAddress before setting
  961. // this handler. Otherwise, we can end up using closed
  962. // handles.
  963. //
  964. //
  965. // Enable receiving datagrams on this device.
  966. //
  967. Status = BowserpTdiSetEventHandler( DeviceObject,
  968. FileObject,
  969. TDI_EVENT_RECEIVE_DATAGRAM,
  970. (PVOID) BowserTdiReceiveDatagramHandler,
  971. TransportName);
  972. if (!NT_SUCCESS(Status)) {
  973. try_return(Status);
  974. }
  975. //
  976. // Tell Netbt to tell us the IP Address of the client.
  977. //
  978. if ( Transport->PagedTransport->Wannish ) {
  979. IO_STATUS_BLOCK IoStatusBlock;
  980. Status = ZwDeviceIoControlFile(
  981. Handle,
  982. NULL,
  983. NULL,
  984. NULL,
  985. &IoStatusBlock,
  986. IOCTL_NETBT_ENABLE_EXTENDED_ADDR,
  987. NULL,
  988. 0,
  989. NULL,
  990. 0 );
  991. if ( !NT_SUCCESS(Status) ) {
  992. dlog(DPRT_TDI, ("%lx: Can't request extended status from netbt\n", TransportName));
  993. try_return(Status);
  994. }
  995. ASSERT(Status != STATUS_PENDING);
  996. }
  997. //
  998. // Save the handles
  999. //
  1000. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1001. TransportName->FileObject = FileObject;
  1002. TransportName->DeviceObject = DeviceObject;
  1003. PagedTransportName->Handle = Handle;
  1004. Handle = NULL;
  1005. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1006. dlog(DPRT_TDI, ("BowserCreateTransportName Succeeded. Name: %lx, Handle: %lx\n", TransportName, PagedTransportName->Handle));
  1007. try_exit:NOTHING;
  1008. } finally {
  1009. if (EABuffer != NULL) {
  1010. FREE_POOL(EABuffer);
  1011. }
  1012. if ( FileObject != NULL ) {
  1013. ObDereferenceObject( FileObject );
  1014. }
  1015. if ( Handle != NULL ) {
  1016. (VOID) ZwClose( Handle );
  1017. }
  1018. if (!NT_SUCCESS(Status)) {
  1019. //
  1020. // Count Number of failed adds of 1D name.
  1021. //
  1022. if ( TransportName->NameType == MasterBrowser ) {
  1023. if (BrOneD.NameAddFailed < BR_ONE_D_STACK_SIZE ) {
  1024. BrOneD.NameAddStack[BrOneD.NameAddFailed] = Status;
  1025. }
  1026. BrOneD.NameAddFailed ++;
  1027. }
  1028. BowserCloseNetbiosAddress( TransportName );
  1029. } else {
  1030. //
  1031. // Count Number of adds of 1D name.
  1032. //
  1033. if ( TransportName->NameType == MasterBrowser ) {
  1034. BrOneD.NameAdded ++;
  1035. }
  1036. }
  1037. }
  1038. return Status;
  1039. }
  1040. VOID
  1041. BowserCloseNetbiosAddress(
  1042. IN PTRANSPORT_NAME TransportName
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. Closes the Netbios Address for a transport name.
  1047. Arguments:
  1048. TransportName - Transport Name whose Netbios address is to be closed.
  1049. Return Value:
  1050. None.
  1051. --*/
  1052. {
  1053. NTSTATUS Status;
  1054. // PTRANSPORT Transport = TransportName->Transport;
  1055. PPAGED_TRANSPORT_NAME PagedTransportName = TransportName->PagedTransportName;
  1056. KAPC_STATE ApcState;
  1057. PAGED_CODE();
  1058. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1059. if (PagedTransportName) {
  1060. if ( PagedTransportName->Handle != NULL ) {
  1061. BOOLEAN ProcessAttached = FALSE;
  1062. if (IoGetCurrentProcess() != BowserFspProcess) {
  1063. KeStackAttachProcess(BowserFspProcess, &ApcState );
  1064. ProcessAttached = TRUE;
  1065. }
  1066. Status = ZwClose( PagedTransportName->Handle );
  1067. if (ProcessAttached) {
  1068. KeUnstackDetachProcess( &ApcState );
  1069. }
  1070. if (!NT_SUCCESS(Status)) {
  1071. dlog(DPRT_TDI, ("BowserCloseNetbiosAddress: Free name %lx failed: %X, %lx Handle: %lx\n", TransportName, Status, PagedTransportName->Handle));
  1072. //
  1073. // Count Number of failed frees of 1D name.
  1074. //
  1075. if ( TransportName->NameType == MasterBrowser ) {
  1076. if (BrOneD.NameFreeFailed < BR_ONE_D_STACK_SIZE ) {
  1077. BrOneD.NameFreeStack[BrOneD.NameFreeFailed] = Status;
  1078. }
  1079. BrOneD.NameFreeFailed ++;
  1080. }
  1081. } else {
  1082. //
  1083. // Count Number of frees of 1D name.
  1084. //
  1085. if ( TransportName->NameType == MasterBrowser ) {
  1086. BrOneD.NameFreed ++;
  1087. }
  1088. }
  1089. PagedTransportName->Handle = NULL;
  1090. }
  1091. }
  1092. //
  1093. // Dereference the FileObject ONLY after the handle is closed.
  1094. // The indication routine references FileObject with no synchronization.
  1095. // By closing the handle first, I know the TDI driver is out of the
  1096. // indication routine before I dereference the FileObject.
  1097. //
  1098. if ( TransportName->FileObject != NULL ) {
  1099. ObDereferenceObject( TransportName->FileObject );
  1100. TransportName->FileObject = NULL;
  1101. }
  1102. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1103. }
  1104. VOID
  1105. BowserCloseAllNetbiosAddresses(
  1106. IN PTRANSPORT Transport
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. This routine closes all the Netbios address this transport has open
  1111. to the TDI driver.
  1112. Arguments:
  1113. Transport - The transport whose Netbios addresses are to be closed.
  1114. Return Value:
  1115. NTSTATUS - Status of resulting operation.
  1116. --*/
  1117. {
  1118. PLIST_ENTRY NameEntry;
  1119. PLIST_ENTRY NextEntry;
  1120. PAGED_CODE();
  1121. dlog(DPRT_TDI,
  1122. ("%s: %ws: BowserCloseAllNetbiosAddresses: Close addresses for transport %lx\n",
  1123. Transport->DomainInfo->DomOemDomainName,
  1124. Transport->PagedTransport->TransportName.Buffer,
  1125. Transport));
  1126. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1127. for (NameEntry = Transport->PagedTransport->NameChain.Flink;
  1128. NameEntry != &Transport->PagedTransport->NameChain;
  1129. NameEntry = NextEntry) {
  1130. PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
  1131. PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
  1132. NextEntry = NameEntry->Flink;
  1133. BowserCloseNetbiosAddress(TransportName);
  1134. }
  1135. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1136. return;
  1137. }
  1138. NTSTATUS
  1139. BowserEnableIpxDatagramSocket(
  1140. IN PTRANSPORT Transport
  1141. )
  1142. {
  1143. NTSTATUS status;
  1144. NWLINK_ACTION action;
  1145. PAGED_CODE( );
  1146. //
  1147. // Put the endpoint in broadcast reception mode.
  1148. //
  1149. action.Header.TransportId = 'XPIM'; // "MIPX"
  1150. action.Header.ActionCode = 0;
  1151. action.Header.Reserved = 0;
  1152. action.OptionType = TRUE;
  1153. action.BufferLength = sizeof(action.Option);
  1154. action.Option = MIPX_RCVBCAST;
  1155. status = BowserIssueTdiAction(
  1156. Transport->IpxSocketDeviceObject,
  1157. Transport->IpxSocketFileObject,
  1158. (PCHAR)&action,
  1159. sizeof(action)
  1160. );
  1161. if ( !NT_SUCCESS(status) ) {
  1162. goto cleanup;
  1163. }
  1164. //
  1165. // Set the default packet type to 20 to force all browser packets
  1166. // through routers.
  1167. //
  1168. action.Header.TransportId = 'XPIM'; // "MIPX"
  1169. action.Header.ActionCode = 0;
  1170. action.Header.Reserved = 0;
  1171. action.OptionType = TRUE;
  1172. action.BufferLength = sizeof(action.Option);
  1173. action.Option = MIPX_SETSENDPTYPE;
  1174. action.Data[0] = IPX_BROADCAST_PACKET;
  1175. status = BowserIssueTdiAction(
  1176. Transport->IpxSocketDeviceObject,
  1177. Transport->IpxSocketFileObject,
  1178. (PCHAR)&action,
  1179. sizeof(action)
  1180. );
  1181. if ( !NT_SUCCESS(status) ) {
  1182. goto cleanup;
  1183. }
  1184. //
  1185. // Register the browser Receive Datagram event handler.
  1186. //
  1187. status = BowserpTdiSetEventHandler(
  1188. Transport->IpxSocketDeviceObject,
  1189. Transport->IpxSocketFileObject,
  1190. TDI_EVENT_RECEIVE_DATAGRAM,
  1191. BowserIpxDatagramHandler,
  1192. Transport
  1193. );
  1194. if ( !NT_SUCCESS(status) ) {
  1195. // INTERNAL_ERROR(
  1196. // ERROR_LEVEL_EXPECTED,
  1197. // "OpenNonNetbiosAddress: set receive datagram event handler failed: %X",
  1198. // status,
  1199. // NULL
  1200. // );
  1201. // SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  1202. goto cleanup;
  1203. }
  1204. return STATUS_SUCCESS;
  1205. //
  1206. // Out-of-line error cleanup.
  1207. //
  1208. cleanup:
  1209. //
  1210. // Something failed. Clean up as appropriate.
  1211. //
  1212. if ( Transport->IpxSocketFileObject != NULL ) {
  1213. ObDereferenceObject( Transport->IpxSocketFileObject );
  1214. Transport->IpxSocketFileObject = NULL;
  1215. }
  1216. if ( Transport->PagedTransport->IpxSocketHandle != NULL ) {
  1217. ZwClose( Transport->PagedTransport->IpxSocketHandle );
  1218. Transport->PagedTransport->IpxSocketHandle = NULL;
  1219. }
  1220. return status;
  1221. }
  1222. NTSTATUS
  1223. OpenIpxSocket (
  1224. OUT PHANDLE Handle,
  1225. OUT PFILE_OBJECT *FileObject,
  1226. OUT PDEVICE_OBJECT *DeviceObject,
  1227. IN PUNICODE_STRING DeviceName,
  1228. IN USHORT Socket
  1229. )
  1230. {
  1231. NTSTATUS status;
  1232. ULONG length;
  1233. PFILE_FULL_EA_INFORMATION ea;
  1234. TA_IPX_ADDRESS ipxAddress;
  1235. OBJECT_ATTRIBUTES objectAttributes;
  1236. IO_STATUS_BLOCK iosb;
  1237. CHAR buffer[sizeof(FILE_FULL_EA_INFORMATION) +
  1238. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1239. sizeof(TA_IPX_ADDRESS)];
  1240. PAGED_CODE( );
  1241. //
  1242. // Build the IPX socket address.
  1243. //
  1244. length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  1245. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1246. sizeof(TA_IPX_ADDRESS);
  1247. ea = (PFILE_FULL_EA_INFORMATION)buffer;
  1248. ea->NextEntryOffset = 0;
  1249. ea->Flags = 0;
  1250. ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1251. ea->EaValueLength = sizeof (TA_IPX_ADDRESS);
  1252. RtlCopyMemory( ea->EaName, TdiTransportAddress, ea->EaNameLength + 1 );
  1253. //
  1254. // Create a copy of the NETBIOS address descriptor in a local
  1255. // first, in order to avoid alignment problems.
  1256. //
  1257. ipxAddress.TAAddressCount = 1;
  1258. ipxAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  1259. ipxAddress.Address[0].AddressLength = sizeof (TDI_ADDRESS_IPX);
  1260. ipxAddress.Address[0].Address[0].NetworkAddress = 0;
  1261. RtlZeroMemory(ipxAddress.Address[0].Address[0].NodeAddress, sizeof(ipxAddress.Address[0].Address[0].NodeAddress));
  1262. ipxAddress.Address[0].Address[0].Socket = Socket;
  1263. RtlCopyMemory(
  1264. &ea->EaName[ea->EaNameLength + 1],
  1265. &ipxAddress,
  1266. sizeof(TA_IPX_ADDRESS)
  1267. );
  1268. InitializeObjectAttributes( &objectAttributes, DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  1269. status = IoCreateFile (
  1270. Handle,
  1271. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access
  1272. &objectAttributes, // object attributes
  1273. &iosb, // returned status information
  1274. NULL, // block size (unused)
  1275. 0, // file attributes
  1276. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  1277. FILE_CREATE, // create disposition
  1278. 0, // create options
  1279. buffer, // EA buffer
  1280. length, // EA length
  1281. CreateFileTypeNone,
  1282. NULL,
  1283. IO_NO_PARAMETER_CHECKING | // All of the buffers are kernel buffers
  1284. IO_CHECK_CREATE_PARAMETERS);// But double check parameter consistancy
  1285. if ( !NT_SUCCESS(status) ) {
  1286. // KdPrint(( "Status of opening ipx socket %x on %wZ is %x\n",
  1287. // Socket, DeviceName, status ));
  1288. return status;
  1289. }
  1290. // KdPrint(( "IPX socket %x opened!\n", Socket ));
  1291. status = ObReferenceObjectByHandle (
  1292. *Handle,
  1293. 0,
  1294. *IoFileObjectType,
  1295. KernelMode,
  1296. (PVOID *)FileObject,
  1297. NULL
  1298. );
  1299. if (!NT_SUCCESS(status)) {
  1300. ZwClose(*Handle);
  1301. *Handle = NULL;
  1302. *DeviceObject = NULL;
  1303. }
  1304. else {
  1305. *DeviceObject = IoGetRelatedDeviceObject(*FileObject);
  1306. }
  1307. return status;
  1308. } // OpenIpxSocket
  1309. VOID
  1310. BowserReferenceTransportName(
  1311. IN PTRANSPORT_NAME TransportName
  1312. )
  1313. {
  1314. InterlockedIncrement(&TransportName->ReferenceCount);
  1315. }
  1316. NTSTATUS
  1317. BowserDereferenceTransportName(
  1318. IN PTRANSPORT_NAME TransportName
  1319. )
  1320. {
  1321. NTSTATUS Status;
  1322. LONG Result;
  1323. PAGED_CODE();
  1324. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1325. if (TransportName->ReferenceCount == 0) {
  1326. InternalError(("Transport Name Reference Count mismatch\n"));
  1327. }
  1328. Result = InterlockedDecrement(&TransportName->ReferenceCount);
  1329. if (Result == 0) {
  1330. Status = BowserFreeTransportName(TransportName);
  1331. } else {
  1332. Status = STATUS_SUCCESS;
  1333. }
  1334. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1335. return Status;
  1336. }
  1337. NTSTATUS
  1338. BowserpTdiRemoveAddresses(
  1339. IN PTRANSPORT Transport
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. This routine removes all the transport names associated with a transport
  1344. Arguments:
  1345. IN PTRANSPORT Transport - Supplies a transport structure describing the
  1346. transport address object to be created.
  1347. Return Value:
  1348. NTSTATUS - Status of resulting operation.
  1349. --*/
  1350. {
  1351. NTSTATUS Status;
  1352. PLIST_ENTRY NameEntry;
  1353. PLIST_ENTRY NextEntry;
  1354. PAGED_CODE();
  1355. dlog(DPRT_TDI,
  1356. ("%s: %ws: BowserpTdiRemoveAddresses: Remove addresses for transport %lx\n",
  1357. Transport->DomainInfo->DomOemDomainName,
  1358. Transport->PagedTransport->TransportName.Buffer,
  1359. Transport));
  1360. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1361. for (NameEntry = Transport->PagedTransport->NameChain.Flink;
  1362. NameEntry != &Transport->PagedTransport->NameChain;
  1363. NameEntry = NextEntry) {
  1364. PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
  1365. PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
  1366. NextEntry = NameEntry->Flink;
  1367. //
  1368. // Remove the TransportName from the list of transport names for
  1369. // this transport.
  1370. //
  1371. ASSERT(PagedTransportName->TransportNext.Flink != NULL);
  1372. RemoveEntryList(&PagedTransportName->TransportNext);
  1373. PagedTransportName->TransportNext.Flink = NULL;
  1374. PagedTransportName->TransportNext.Blink = NULL;
  1375. //
  1376. // Since we delinked it, we need to dereference it.
  1377. //
  1378. Status = BowserDereferenceTransportName(TransportName);
  1379. if (!NT_SUCCESS(Status)) {
  1380. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1381. return(Status);
  1382. }
  1383. }
  1384. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1385. return STATUS_SUCCESS;
  1386. }
  1387. PTRANSPORT_NAME
  1388. BowserFindTransportName(
  1389. IN PTRANSPORT Transport,
  1390. IN PBOWSER_NAME Name
  1391. )
  1392. /*++
  1393. Routine Description:
  1394. This routine looks up a given browser name to find its associated
  1395. transport address.
  1396. Arguments:
  1397. IN PTRANSPORT Transport - Supplies a transport structure describing the
  1398. transport address object to be created.
  1399. IN PBOWSER_NAME Name - Supplies the name to look up.
  1400. Return Value:
  1401. The transport address found, or null.
  1402. --*/
  1403. {
  1404. PLIST_ENTRY NameEntry;
  1405. PTRANSPORT_NAME RetValue = NULL;
  1406. PAGED_CODE();
  1407. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1408. try {
  1409. for (NameEntry = Transport->PagedTransport->NameChain.Flink;
  1410. NameEntry != &Transport->PagedTransport->NameChain;
  1411. NameEntry = NameEntry->Flink) {
  1412. PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
  1413. PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
  1414. if (PagedTransportName->Name == Name) {
  1415. try_return(RetValue = TransportName);
  1416. }
  1417. try_exit:NOTHING;
  1418. }
  1419. } finally {
  1420. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1421. }
  1422. return RetValue;
  1423. }
  1424. NTSTATUS
  1425. BowserFreeTransportName(
  1426. IN PTRANSPORT_NAME TransportName
  1427. )
  1428. {
  1429. PTRANSPORT Transport = TransportName->Transport;
  1430. PBOWSER_NAME Name = NULL;
  1431. PPAGED_TRANSPORT_NAME PagedTransportName = TransportName->PagedTransportName;
  1432. PAGED_CODE();
  1433. dlog(DPRT_TDI,
  1434. ("%s: %ws: BowserFreeTransportName: Free name %lx\n",
  1435. Transport->DomainInfo->DomOemDomainName,
  1436. Transport->PagedTransport->TransportName.Buffer,
  1437. TransportName));
  1438. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1439. //
  1440. // Close the handle to the TDI driver.
  1441. //
  1442. BowserCloseNetbiosAddress( TransportName );
  1443. //
  1444. // If we received a message which re-referenced this transport name,
  1445. // just return now. We'll be back when the reference count gets
  1446. // re-dereferenced to zero.
  1447. //
  1448. if ( TransportName->ReferenceCount != 0 ) {
  1449. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1450. return STATUS_SUCCESS;
  1451. }
  1452. ASSERT (TransportName->ReferenceCount == 0);
  1453. if (PagedTransportName) {
  1454. //
  1455. // If this transport name has not yet been delinked,
  1456. // delink it.
  1457. //
  1458. if ( PagedTransportName->TransportNext.Flink != NULL ) {
  1459. // This should only happen on a failed transport name creation.
  1460. RemoveEntryList(&PagedTransportName->TransportNext);
  1461. PagedTransportName->TransportNext.Flink = NULL;
  1462. PagedTransportName->TransportNext.Blink = NULL;
  1463. }
  1464. RemoveEntryList(&PagedTransportName->NameNext);
  1465. //
  1466. // We're removing an OtherDomain - we can remove the reference to
  1467. // the discardable code section that was applied when the name was
  1468. // created.
  1469. //
  1470. if (PagedTransportName->Name->NameType == OtherDomain) {
  1471. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  1472. }
  1473. Name = PagedTransportName->Name;
  1474. FREE_POOL(PagedTransportName);
  1475. }
  1476. if (Name != NULL) {
  1477. switch ( Name->NameType ) {
  1478. case ComputerName:
  1479. Transport->ComputerName = NULL;
  1480. break;
  1481. case PrimaryDomain:
  1482. if ( Transport->PrimaryDomain == TransportName ) {
  1483. Transport->PrimaryDomain = Transport->AltPrimaryDomain;
  1484. Transport->AltPrimaryDomain = NULL;
  1485. }
  1486. if ( Transport->AltPrimaryDomain == TransportName ) {
  1487. Transport->AltPrimaryDomain = NULL;
  1488. }
  1489. break;
  1490. case MasterBrowser:
  1491. Transport->MasterBrowser = NULL;
  1492. break;
  1493. case BrowserElection:
  1494. Transport->BrowserElection = NULL;
  1495. break;
  1496. case PrimaryDomainBrowser:
  1497. Transport->PagedTransport->IsPrimaryDomainController = FALSE;
  1498. //
  1499. // Notify services we are no longer a PDC
  1500. //
  1501. BowserSendPnp(
  1502. NlPnpNewRole,
  1503. &Transport->DomainInfo->DomUnicodeDomainName,
  1504. &Transport->PagedTransport->TransportName,
  1505. BowserTransportFlags(Transport->PagedTransport) );
  1506. break;
  1507. }
  1508. BowserDereferenceName(Name);
  1509. }
  1510. FREE_POOL(TransportName);
  1511. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1512. dlog(DPRT_TDI,
  1513. ("%s: %ws: BowserFreeTransportName: Free name %lx completed\n",
  1514. Transport->DomainInfo->DomOemDomainName,
  1515. Transport->PagedTransport->TransportName.Buffer,
  1516. TransportName));
  1517. return(STATUS_SUCCESS);
  1518. }
  1519. VOID
  1520. BowserDeleteTransport(
  1521. IN PTRANSPORT Transport
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. Delete a transport.
  1526. The caller should have a single reference to the transport. The actual
  1527. transport structure will be deleted when that reference goes away.
  1528. This routine will decrement the global reference made in
  1529. BowserTdiAllocateTransport
  1530. Arguments:
  1531. IN Transport - Supplies a transport structure to be deleted.
  1532. Return Value:
  1533. None.
  1534. --*/
  1535. {
  1536. LARGE_INTEGER Interval;
  1537. PPAGED_TRANSPORT PagedTransport;
  1538. PAGED_CODE();
  1539. //
  1540. // Do cleanup of the PagedTransport structure
  1541. //
  1542. PagedTransport = Transport->PagedTransport;
  1543. if ( PagedTransport != NULL ) {
  1544. //
  1545. // Notify services that this transport is now unbound
  1546. //
  1547. BowserSendPnp(
  1548. NlPnpTransportUnbind,
  1549. NULL, // All hosted domains
  1550. &PagedTransport->TransportName,
  1551. BowserTransportFlags(PagedTransport) );
  1552. //
  1553. // Prevent BowserFindTransport from adding any new references to the transport
  1554. //
  1555. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1556. if (!PagedTransport->DeletedTransport ) {
  1557. //
  1558. // Don't actually delink the entry since routines like
  1559. // BowserForEachTransport expect a reference to this transport
  1560. // to be enough to keep the GlobalNext list intact.
  1561. //
  1562. PagedTransport->DeletedTransport = TRUE;
  1563. //
  1564. // Remove the global reference to the transport.
  1565. //
  1566. // Avoid removing the global reference if we aren't in the global list.
  1567. //
  1568. if ( !IsListEmpty( &PagedTransport->GlobalNext) ) {
  1569. BowserDereferenceTransport( Transport );
  1570. }
  1571. }
  1572. //
  1573. // Close all handles to the TDI driver so we won't get any indications after
  1574. // we start cleaning up the Transport structure in BowserpFreeTransport.
  1575. //
  1576. BowserCloseAllNetbiosAddresses( Transport );
  1577. if ( PagedTransport->IpxSocketHandle != NULL) {
  1578. NTSTATUS LocalStatus;
  1579. BOOLEAN ProcessAttached = FALSE;
  1580. KAPC_STATE ApcState;
  1581. if (IoGetCurrentProcess() != BowserFspProcess) {
  1582. KeStackAttachProcess(BowserFspProcess, &ApcState );
  1583. ProcessAttached = TRUE;
  1584. }
  1585. LocalStatus = ZwClose(PagedTransport->IpxSocketHandle);
  1586. ASSERT(NT_SUCCESS(LocalStatus));
  1587. if (ProcessAttached) {
  1588. KeUnstackDetachProcess( &ApcState );
  1589. }
  1590. PagedTransport->IpxSocketHandle = NULL;
  1591. if ( Transport->IpxSocketFileObject != NULL ) {
  1592. ObDereferenceObject( Transport->IpxSocketFileObject );
  1593. Transport->IpxSocketFileObject = NULL;
  1594. }
  1595. Transport->IpxSocketDeviceObject = NULL;
  1596. }
  1597. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1598. }
  1599. //
  1600. // Uninitialize the timers to ensure we aren't in a timer routine while
  1601. // we are cleaning up.
  1602. //
  1603. BowserUninitializeTimer(&Transport->ElectionTimer);
  1604. BowserUninitializeTimer(&Transport->FindMasterTimer);
  1605. //
  1606. // Delete any mailslot messages queued to the netlogon service.
  1607. //
  1608. BowserNetlogonDeleteTransportFromMessageQueue ( Transport );
  1609. //
  1610. // Loop until this transport has the last reference to each of the transport
  1611. // names. Above, we prevented any new references. Here we ensure that
  1612. // all of the existing references go away.
  1613. //
  1614. // If there is an existing reference to the transport name, the holder
  1615. // of that reference can feel free to add a reference to
  1616. // TRANSPORT_NAME->Transport.
  1617. //
  1618. if ( PagedTransport != NULL ) {
  1619. PLIST_ENTRY NameEntry;
  1620. PLIST_ENTRY NextEntry;
  1621. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1622. for (NameEntry = Transport->PagedTransport->NameChain.Flink;
  1623. NameEntry &&
  1624. (NameEntry != &Transport->PagedTransport->NameChain);
  1625. NameEntry = NextEntry) {
  1626. PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
  1627. PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
  1628. NextEntry = NameEntry->Flink;
  1629. if ( TransportName->ReferenceCount != 1 ) {
  1630. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1631. Interval.QuadPart = -1000*1000; // .1 second
  1632. KeDelayExecutionThread( KernelMode, FALSE, &Interval );
  1633. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1634. NextEntry = Transport->PagedTransport->NameChain.Flink;
  1635. }
  1636. }
  1637. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1638. }
  1639. //
  1640. // Loop until our caller has the last outstanding reference.
  1641. // This loop is the only thing preventing the driver from unloading while there
  1642. // are still references outstanding.
  1643. //
  1644. while ( Transport->ReferenceCount != 1) {
  1645. Interval.QuadPart = -1000*1000; // .01 second
  1646. KeDelayExecutionThread( KernelMode, FALSE, &Interval );
  1647. }
  1648. }
  1649. VOID
  1650. BowserpFreeTransport(
  1651. IN PTRANSPORT Transport
  1652. )
  1653. {
  1654. PAGED_CODE();
  1655. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1656. //
  1657. // Free the Paged transport, if necessary.
  1658. //
  1659. if (Transport->PagedTransport != NULL) {
  1660. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  1661. //
  1662. // Remove the entry from the global list if it is in it.
  1663. //
  1664. if ( !IsListEmpty( &PagedTransport->GlobalNext ) ) {
  1665. ASSERT( PagedTransport->DeletedTransport );
  1666. RemoveEntryList(&PagedTransport->GlobalNext);
  1667. }
  1668. //
  1669. // Remove the Adresses.
  1670. //
  1671. // Do this in a separate step from the Close in BowserDeleteTransport
  1672. // above to ensure the PrimaryDomain and ComputerName fields don't
  1673. // get cleared until all possible references are removed.
  1674. //
  1675. if (!IsListEmpty( &PagedTransport->NameChain)) {
  1676. BowserpTdiRemoveAddresses(Transport);
  1677. }
  1678. BowserDeleteGenericTable(&PagedTransport->AnnouncementTable);
  1679. BowserDeleteGenericTable(&PagedTransport->DomainTable);
  1680. if (PagedTransport->BrowserServerListBuffer != NULL) {
  1681. BowserFreeBrowserServerList(
  1682. PagedTransport->BrowserServerListBuffer,
  1683. PagedTransport->BrowserServerListLength
  1684. );
  1685. }
  1686. FREE_POOL(PagedTransport);
  1687. }
  1688. if ( Transport->DomainInfo != NULL ) {
  1689. BowserDereferenceDomain( Transport->DomainInfo );
  1690. }
  1691. ExDeleteResourceLite(&Transport->BrowserServerListResource);
  1692. UNINITIALIZE_ANNOUNCE_DATABASE(Transport);
  1693. ExDeleteResourceLite(&Transport->Lock);
  1694. BowserUninitializeIrpQueue(&Transport->BecomeBackupQueue);
  1695. BowserUninitializeIrpQueue(&Transport->BecomeMasterQueue);
  1696. BowserUninitializeIrpQueue(&Transport->FindMasterQueue);
  1697. BowserUninitializeIrpQueue(&Transport->WaitForMasterAnnounceQueue);
  1698. BowserUninitializeIrpQueue(&Transport->ChangeRoleQueue);
  1699. BowserUninitializeIrpQueue(&Transport->WaitForNewMasterNameQueue );
  1700. FREE_POOL(Transport);
  1701. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  1702. }
  1703. NTSTATUS
  1704. BowserpTdiSetEventHandler (
  1705. IN PDEVICE_OBJECT DeviceObject,
  1706. IN PFILE_OBJECT FileObject,
  1707. IN ULONG EventType,
  1708. IN PVOID EventHandler,
  1709. IN PVOID Context
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. This routine registers an event handler with a TDI transport provider.
  1714. Arguments:
  1715. IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
  1716. IN PFILE_OBJECT FileObject - Supplies the address object's file object.
  1717. IN ULONG EventType, - Supplies the type of event.
  1718. IN PVOID EventHandler - Supplies the event handler.
  1719. Return Value:
  1720. NTSTATUS - Final status of the set event operation
  1721. --*/
  1722. {
  1723. NTSTATUS Status;
  1724. PIRP Irp;
  1725. PAGED_CODE();
  1726. Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  1727. if (Irp == NULL) {
  1728. return(STATUS_INSUFFICIENT_RESOURCES);
  1729. }
  1730. TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
  1731. NULL, NULL,
  1732. EventType, EventHandler, Context);
  1733. Status = BowserSubmitTdiRequest(FileObject, Irp);
  1734. IoFreeIrp(Irp);
  1735. return Status;
  1736. }
  1737. NTSTATUS
  1738. BowserIssueTdiAction (
  1739. IN PDEVICE_OBJECT DeviceObject,
  1740. IN PFILE_OBJECT FileObject,
  1741. IN PVOID Action,
  1742. IN ULONG ActionSize
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. This routine registers an event handler with a TDI transport provider.
  1747. Arguments:
  1748. IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
  1749. IN PFILE_OBJECT FileObject - Supplies the address object's file object.
  1750. IN ULONG EventType, - Supplies the type of event.
  1751. IN PVOID EventHandler - Supplies the event handler.
  1752. Return Value:
  1753. NTSTATUS - Final status of the set event operation
  1754. --*/
  1755. {
  1756. NTSTATUS status;
  1757. PIRP irp;
  1758. // PIO_STACK_LOCATION irpSp;
  1759. PMDL mdl;
  1760. PAGED_CODE();
  1761. irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  1762. if (irp == NULL) {
  1763. return STATUS_INSUFFICIENT_RESOURCES;
  1764. }
  1765. //
  1766. // Allocate and build an MDL that we'll use to describe the output
  1767. // buffer for the request.
  1768. //
  1769. mdl = IoAllocateMdl( Action, ActionSize, FALSE, FALSE, NULL );
  1770. if ( mdl == NULL ) {
  1771. IoFreeIrp( irp );
  1772. return STATUS_INSUFFICIENT_RESOURCES;
  1773. }
  1774. MmBuildMdlForNonPagedPool( mdl );
  1775. TdiBuildAction(
  1776. irp,
  1777. DeviceObject,
  1778. FileObject,
  1779. NULL,
  1780. NULL,
  1781. mdl
  1782. );
  1783. irp->AssociatedIrp.SystemBuffer = Action;
  1784. if (irp == NULL) {
  1785. return(STATUS_INSUFFICIENT_RESOURCES);
  1786. }
  1787. status = BowserSubmitTdiRequest(FileObject, irp);
  1788. IoFreeIrp(irp);
  1789. IoFreeMdl(mdl);
  1790. return status;
  1791. }
  1792. NTSTATUS
  1793. BowserBuildTransportAddress (
  1794. IN OUT PANSI_STRING Address,
  1795. IN PUNICODE_STRING Name,
  1796. IN DGRECEIVER_NAME_TYPE NameType,
  1797. IN PTRANSPORT Transport
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. This routine takes a computer name (PUNICODE_STRING) and converts it into an
  1802. acceptable form for passing in as transport address.
  1803. Arguments:
  1804. OUT PTA_NETBIOS_ADDRESS RemoteAddress, - Supplies the structure to fill in
  1805. IN PUNICODE_STRING Name - Supplies the name to put into the transport
  1806. Please note that it is CRITICAL that the TA_NETBIOS_ADDRESS pointed to by
  1807. RemoteAddress be of sufficient size to hold the full network name.
  1808. Return Value:
  1809. None.
  1810. --*/
  1811. {
  1812. NTSTATUS Status;
  1813. OEM_STRING NetBiosName;
  1814. PTRANSPORT_ADDRESS RemoteAddress = (PTRANSPORT_ADDRESS)Address->Buffer;
  1815. PTDI_ADDRESS_NETBIOS NetbiosAddress = (PTDI_ADDRESS_NETBIOS)&RemoteAddress->Address[0].Address[0];
  1816. PAGED_CODE();
  1817. //
  1818. // Ensure there is room for this address.
  1819. //
  1820. if ( Address->MaximumLength < sizeof(TA_NETBIOS_ADDRESS) ) {
  1821. return STATUS_BUFFER_TOO_SMALL;
  1822. }
  1823. RemoteAddress->TAAddressCount = 1;
  1824. RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1825. RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
  1826. Address->Length = sizeof(TA_NETBIOS_ADDRESS);
  1827. NetBiosName.Length = 0;
  1828. NetBiosName.MaximumLength = NETBIOS_NAME_LEN;
  1829. NetBiosName.Buffer = NetbiosAddress->NetbiosName;
  1830. //
  1831. // Domain announcements are to a constant Netbios name address.
  1832. //
  1833. switch (NameType) {
  1834. case DomainAnnouncement:
  1835. ASSERT (strlen(DOMAIN_ANNOUNCEMENT_NAME) == NETBIOS_NAME_LEN);
  1836. RtlCopyMemory(NetBiosName.Buffer, DOMAIN_ANNOUNCEMENT_NAME, strlen(DOMAIN_ANNOUNCEMENT_NAME));
  1837. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  1838. break;
  1839. //
  1840. // All other names are upper case, OEM, and trailing blank filled.
  1841. //
  1842. default:
  1843. if (RtlUnicodeStringToOemSize(Name) > NETBIOS_NAME_LEN) {
  1844. return STATUS_BAD_NETWORK_PATH;
  1845. }
  1846. Status = RtlUpcaseUnicodeStringToOemString(&NetBiosName, Name, FALSE);
  1847. if (!NT_SUCCESS(Status)) {
  1848. return Status;
  1849. }
  1850. RtlCopyMemory(&NetBiosName.Buffer[NetBiosName.Length], " ",
  1851. NETBIOS_NAME_LEN-NetBiosName.Length);
  1852. switch (NameType) {
  1853. case ComputerName:
  1854. case AlternateComputerName:
  1855. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = WORKSTATION_SIGNATURE;
  1856. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1857. break;
  1858. case DomainName:
  1859. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = DOMAIN_CONTROLLER_SIGNATURE;
  1860. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  1861. break;
  1862. case BrowserServer:
  1863. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = SERVER_SIGNATURE;
  1864. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1865. break;
  1866. case MasterBrowser:
  1867. if (Transport->PagedTransport->Flags & DIRECT_HOST_IPX) {
  1868. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = WORKSTATION_SIGNATURE;
  1869. } else {
  1870. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = MASTER_BROWSER_SIGNATURE;
  1871. }
  1872. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1873. break;
  1874. case PrimaryDomain:
  1875. case OtherDomain:
  1876. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = PRIMARY_DOMAIN_SIGNATURE;
  1877. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  1878. break;
  1879. case PrimaryDomainBrowser:
  1880. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = PRIMARY_CONTROLLER_SIGNATURE;
  1881. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1882. break;
  1883. case BrowserElection:
  1884. if (Transport->PagedTransport->Flags & DIRECT_HOST_IPX) {
  1885. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = WORKSTATION_SIGNATURE;
  1886. } else {
  1887. NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = BROWSER_ELECTION_SIGNATURE;
  1888. }
  1889. NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  1890. break;
  1891. }
  1892. break;
  1893. }
  1894. return STATUS_SUCCESS;
  1895. }
  1896. NTSTATUS
  1897. BowserUpdateProviderInformation(
  1898. IN OUT PPAGED_TRANSPORT PagedTransport
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. This routine updates status bits in the PagedTransport based on querying
  1903. the TDI driver.
  1904. Most importantly, the transport will be disabled if the provider is RAS or
  1905. doesn't yet have an IP address.
  1906. A goal of this routine is to handle the case where there are multiple IP
  1907. net cards on the same subnet. In that case, we want only one such net
  1908. card enabled for each emulated domain.
  1909. Arguments:
  1910. PagedTransport - Transport to update
  1911. Return Value:
  1912. Status of operation.
  1913. --*/
  1914. {
  1915. NTSTATUS Status;
  1916. TDI_PROVIDER_INFO ProviderInfo;
  1917. ULONG OldIpSubnetNumber;
  1918. BOOLEAN DisableThisTransport = FALSE;
  1919. PLIST_ENTRY TransportEntry;
  1920. PPAGED_TRANSPORT CurrentPagedTransport;
  1921. PAGED_CODE();
  1922. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  1923. //
  1924. // Find out about the transport.
  1925. //
  1926. OldIpSubnetNumber = PagedTransport->IpSubnetNumber;
  1927. Status = BowserDetermineProviderInformation(
  1928. &PagedTransport->TransportName,
  1929. &ProviderInfo,
  1930. &PagedTransport->IpSubnetNumber );
  1931. if (!NT_SUCCESS(Status)) {
  1932. goto ReturnStatus;
  1933. }
  1934. //
  1935. // We can only talk to transports that support a max datagram size.
  1936. //
  1937. if (ProviderInfo.MaxDatagramSize == 0) {
  1938. Status = STATUS_BAD_REMOTE_ADAPTER;
  1939. goto ReturnStatus;
  1940. }
  1941. PagedTransport->NonPagedTransport->DatagramSize = ProviderInfo.MaxDatagramSize;
  1942. //
  1943. // Remember various attributes of the provider
  1944. // (Never disable the PointToPoint bit. NetBt forgets it when the
  1945. // RAS phone is hung up.)
  1946. PagedTransport->Wannish = (BOOLEAN)((ProviderInfo.ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) != 0);
  1947. if (ProviderInfo.ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
  1948. PagedTransport->PointToPoint = TRUE;
  1949. }
  1950. //
  1951. // If this is a RAS transport or the IP Address is not yet known,
  1952. // disable browsing on the transport.
  1953. //
  1954. if ( PagedTransport->PointToPoint ||
  1955. PagedTransport->IpSubnetNumber == 0 ) {
  1956. DisableThisTransport = TRUE;
  1957. }
  1958. //
  1959. // If this isn't an IP transport, we're done.
  1960. //
  1961. if ( PagedTransport->IpSubnetNumber == BOWSER_NON_IP_SUBNET ) {
  1962. goto ReturnStatus;
  1963. }
  1964. //
  1965. // In the loop below, we use OldIpSubnetNumber to determine if another
  1966. // transport should be enabled on that subnet. If that will NEVER be
  1967. // appropriate, flag OldIpSubnetNumber now.
  1968. //
  1969. if ( OldIpSubnetNumber == 0 ||
  1970. PagedTransport->DisabledTransport ||
  1971. PagedTransport->IpSubnetNumber == OldIpSubnetNumber ) {
  1972. OldIpSubnetNumber = BOWSER_NON_IP_SUBNET;
  1973. }
  1974. //
  1975. // Loop through the transports enabling/disabling them as indicated by
  1976. // the comments below.
  1977. //
  1978. for (TransportEntry = BowserTransportHead.Flink ;
  1979. TransportEntry != &BowserTransportHead ;
  1980. TransportEntry = CurrentPagedTransport->GlobalNext.Flink ) {
  1981. CurrentPagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
  1982. //
  1983. // Ignore deleted transports.
  1984. //
  1985. if ( CurrentPagedTransport->DeletedTransport ) {
  1986. continue;
  1987. }
  1988. //
  1989. // If this transport isn't an IP transport,
  1990. // or this transport is a RAS transport,
  1991. // or this transport is the transport passed in,
  1992. // skip it and go on to the next one.
  1993. //
  1994. if ( CurrentPagedTransport->IpSubnetNumber == BOWSER_NON_IP_SUBNET ||
  1995. CurrentPagedTransport->PointToPoint ||
  1996. CurrentPagedTransport == PagedTransport ) {
  1997. continue;
  1998. }
  1999. //
  2000. // Special case this transport if it's currently disabled
  2001. //
  2002. if ( CurrentPagedTransport->DisabledTransport ) {
  2003. //
  2004. // If this transport is disabled and the transport passed in
  2005. // used to be the enabled transport for the subnet,
  2006. // enable the transport
  2007. //
  2008. if ( CurrentPagedTransport->IpSubnetNumber == OldIpSubnetNumber ) {
  2009. CurrentPagedTransport->DisabledTransport = FALSE;
  2010. }
  2011. //
  2012. // In any case,
  2013. // that's all we need to do for a disabled transport.
  2014. //
  2015. continue;
  2016. }
  2017. //
  2018. // If this transport is an enabled transport for the subnet of the one
  2019. // passed in,
  2020. // And this transport is for the same emulated domain as the one
  2021. // passed in,
  2022. // then disable the one passed in.
  2023. //
  2024. if ( CurrentPagedTransport->IpSubnetNumber ==
  2025. PagedTransport->IpSubnetNumber &&
  2026. CurrentPagedTransport->NonPagedTransport->DomainInfo == PagedTransport->NonPagedTransport->DomainInfo ) {
  2027. DisableThisTransport = TRUE;
  2028. }
  2029. }
  2030. //
  2031. // Cleanup
  2032. //
  2033. ReturnStatus:
  2034. //
  2035. // If we're disabling a previously enabled transport,
  2036. // ensure we're not the master browser.
  2037. //
  2038. if ( DisableThisTransport && !PagedTransport->DisabledTransport ) {
  2039. PagedTransport->DisabledTransport = DisableThisTransport;
  2040. BowserLoseElection( PagedTransport->NonPagedTransport );
  2041. } else {
  2042. PagedTransport->DisabledTransport = DisableThisTransport;
  2043. }
  2044. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2045. return Status;
  2046. }
  2047. NTSTATUS
  2048. BowserDetermineProviderInformation(
  2049. IN PUNICODE_STRING TransportName,
  2050. OUT PTDI_PROVIDER_INFO ProviderInfo,
  2051. OUT PULONG IpSubnetNumber
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. This routine will determine provider information about a transport.
  2056. Arguments:
  2057. TransportName - Supplies the name of the transport provider
  2058. ProviderInfo - Returns information about the provider
  2059. IpSubnetNumber - returns the Ip Subnet Number of this transport.
  2060. BOWSER_NON_IP_SUBNET - If this isn't an IP transport
  2061. 0 - If the IP address isn't yet set
  2062. Otherwise - the IP address anded with the subnet mask
  2063. Return Value:
  2064. Status of operation.
  2065. --*/
  2066. {
  2067. HANDLE TransportHandle = NULL;
  2068. PFILE_OBJECT TransportObject = NULL;
  2069. OBJECT_ATTRIBUTES ObjAttributes;
  2070. IO_STATUS_BLOCK IoStatusBlock;
  2071. PIRP Irp;
  2072. PDEVICE_OBJECT DeviceObject;
  2073. PMDL Mdl = NULL;
  2074. NTSTATUS Status = STATUS_SUCCESS;
  2075. PAGED_CODE();
  2076. InitializeObjectAttributes (&ObjAttributes,
  2077. TransportName, // Name
  2078. OBJ_CASE_INSENSITIVE, // Attributes
  2079. NULL, // RootDirectory
  2080. NULL); // SecurityDescriptor
  2081. Status = IoCreateFile(&TransportHandle, // Handle
  2082. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  2083. &ObjAttributes, // Object Attributes
  2084. &IoStatusBlock, // Final I/O status block
  2085. NULL, // Allocation Size
  2086. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  2087. FILE_SHARE_READ, // Sharing attributes
  2088. FILE_OPEN_IF, // Create disposition
  2089. 0, // CreateOptions
  2090. NULL, // EA Buffer
  2091. 0, // EA Buffer Length
  2092. CreateFileTypeNone,
  2093. NULL,
  2094. IO_NO_PARAMETER_CHECKING | // All of the buffers are kernel buffers
  2095. IO_CHECK_CREATE_PARAMETERS);// But double check parameter consistancy
  2096. if (!NT_SUCCESS(Status)) {
  2097. goto ReturnStatus;
  2098. }
  2099. Status = ObReferenceObjectByHandle (
  2100. TransportHandle,
  2101. 0,
  2102. *IoFileObjectType,
  2103. KernelMode,
  2104. (PVOID *)&TransportObject,
  2105. NULL
  2106. );
  2107. if (!NT_SUCCESS(Status)) {
  2108. goto ReturnStatus;
  2109. }
  2110. DeviceObject = IoGetRelatedDeviceObject(TransportObject);
  2111. Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  2112. if (Irp == NULL) {
  2113. Status = STATUS_INSUFFICIENT_RESOURCES;
  2114. goto ReturnStatus;
  2115. }
  2116. //
  2117. // Allocate an MDL to hold the provider info.
  2118. //
  2119. Mdl = IoAllocateMdl(ProviderInfo, sizeof(TDI_PROVIDER_INFO),
  2120. FALSE,
  2121. FALSE,
  2122. NULL);
  2123. if (Mdl == NULL) {
  2124. IoFreeIrp(Irp);
  2125. Status = STATUS_INSUFFICIENT_RESOURCES;
  2126. goto ReturnStatus;
  2127. }
  2128. MmBuildMdlForNonPagedPool(Mdl);
  2129. TdiBuildQueryInformation(Irp, DeviceObject, TransportObject,
  2130. NULL, NULL,
  2131. TDI_QUERY_PROVIDER_INFORMATION, Mdl);
  2132. Status = BowserSubmitTdiRequest(TransportObject, Irp);
  2133. IoFreeIrp(Irp);
  2134. //
  2135. // Get the IP address for this Transport.
  2136. //
  2137. if ( (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) == 0) {
  2138. *IpSubnetNumber = BOWSER_NON_IP_SUBNET;
  2139. } else {
  2140. NTSTATUS TempStatus;
  2141. IO_STATUS_BLOCK IoStatusBlock;
  2142. ULONG IpAddressBuffer[2]; // IpAddress followed by subnet mask
  2143. TempStatus = ZwDeviceIoControlFile(
  2144. TransportHandle,
  2145. NULL,
  2146. NULL,
  2147. NULL,
  2148. &IoStatusBlock,
  2149. IOCTL_NETBT_GET_IP_SUBNET,
  2150. NULL,
  2151. 0,
  2152. &IpAddressBuffer,
  2153. sizeof(IpAddressBuffer) );
  2154. if ( !NT_SUCCESS(TempStatus) ) {
  2155. *IpSubnetNumber = BOWSER_NON_IP_SUBNET;
  2156. } else {
  2157. ASSERT(TempStatus != STATUS_PENDING);
  2158. *IpSubnetNumber = IpAddressBuffer[0] & IpAddressBuffer[1];
  2159. }
  2160. }
  2161. ReturnStatus:
  2162. if (Mdl != NULL) {
  2163. IoFreeMdl(Mdl);
  2164. }
  2165. if (TransportObject != NULL) {
  2166. ObDereferenceObject(TransportObject);
  2167. }
  2168. if (TransportHandle != NULL) {
  2169. ZwClose(TransportHandle);
  2170. }
  2171. return(Status);
  2172. }
  2173. PTRANSPORT
  2174. BowserFindTransport (
  2175. IN PUNICODE_STRING TransportName,
  2176. IN PUNICODE_STRING EmulatedDomainName OPTIONAL
  2177. )
  2178. /*++
  2179. Routine Description:
  2180. This routine will locate a transport in the bowsers transport list.
  2181. Arguments:
  2182. TransportName - Supplies the name of the transport provider
  2183. EmulatedDomainName - Specifies the emulated domain whose transport is to be found.
  2184. Return Value:
  2185. PTRANSPORT - NULL if no transport was found, TRUE if transport was found.
  2186. --*/
  2187. {
  2188. PLIST_ENTRY TransportEntry;
  2189. PTRANSPORT Transport = NULL;
  2190. PPAGED_TRANSPORT PagedTransport = NULL;
  2191. PDOMAIN_INFO DomainInfo = NULL;
  2192. PAGED_CODE();
  2193. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2194. try {
  2195. //
  2196. // Find the requested domain.
  2197. //
  2198. DomainInfo = BowserFindDomain( EmulatedDomainName );
  2199. if ( DomainInfo != NULL ) {
  2200. for (TransportEntry = BowserTransportHead.Flink ;
  2201. TransportEntry != &BowserTransportHead ;
  2202. TransportEntry = TransportEntry->Flink) {
  2203. PagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
  2204. //
  2205. // Ignore deleted transports.
  2206. //
  2207. if ( PagedTransport->DeletedTransport ) {
  2208. continue;
  2209. }
  2210. if ( PagedTransport->NonPagedTransport->DomainInfo == DomainInfo &&
  2211. RtlEqualUnicodeString(TransportName,
  2212. &PagedTransport->TransportName, TRUE)) {
  2213. Transport = PagedTransport->NonPagedTransport;
  2214. dprintf(DPRT_REF, ("Call Reference transport %lx from BowserFindTransport.\n", Transport));
  2215. BowserReferenceTransport( Transport );
  2216. try_return(Transport);
  2217. }
  2218. }
  2219. }
  2220. try_return(Transport = NULL);
  2221. try_exit:NOTHING;
  2222. } finally {
  2223. if ( DomainInfo != NULL ) {
  2224. BowserDereferenceDomain( DomainInfo );
  2225. }
  2226. ExReleaseResourceLite (&BowserTransportDatabaseResource);
  2227. }
  2228. return Transport;
  2229. }
  2230. NTSTATUS
  2231. BowserForEachTransportInDomain (
  2232. IN PDOMAIN_INFO DomainInfo,
  2233. IN PTRANSPORT_ENUM_ROUTINE Routine,
  2234. IN OUT PVOID Context
  2235. )
  2236. /*++
  2237. Routine Description:
  2238. This routine will enumerate the transports and call back the enum
  2239. routine provided with each transport.
  2240. Arguments:
  2241. DomainInfo - Only call 'Routine' for transport in this domain.
  2242. Routine - Routine to call for each transport
  2243. Context - Parameter to pass to 'Routine'
  2244. Return Value:
  2245. NTSTATUS - Final status of request.
  2246. --*/
  2247. {
  2248. PLIST_ENTRY TransportEntry, NextEntry;
  2249. PTRANSPORT Transport = NULL;
  2250. PPAGED_TRANSPORT PagedTransport = NULL;
  2251. NTSTATUS Status = STATUS_SUCCESS;
  2252. PAGED_CODE();
  2253. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2254. for (TransportEntry = BowserTransportHead.Flink ;
  2255. TransportEntry != &BowserTransportHead ;
  2256. TransportEntry = NextEntry) {
  2257. PagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
  2258. Transport = PagedTransport->NonPagedTransport;
  2259. //
  2260. // Ignore deleted transports.
  2261. //
  2262. if ( PagedTransport->DeletedTransport ) {
  2263. NextEntry = PagedTransport->GlobalNext.Flink;
  2264. continue;
  2265. }
  2266. //
  2267. // If transport isn't in the specified domain,
  2268. // ignore it.
  2269. //
  2270. if ( Transport->DomainInfo != DomainInfo ) {
  2271. NextEntry = PagedTransport->GlobalNext.Flink;
  2272. continue;
  2273. }
  2274. dprintf(DPRT_REF, ("Call Reference transport %lx from BowserForEachTransportInDomain.\n", Transport));
  2275. BowserReferenceTransport(Transport);
  2276. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2277. Status = (Routine)(Transport, Context);
  2278. if (!NT_SUCCESS(Status)) {
  2279. BowserDereferenceTransport(Transport);
  2280. return Status;
  2281. }
  2282. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2283. NextEntry = PagedTransport->GlobalNext.Flink;
  2284. BowserDereferenceTransport(Transport);
  2285. }
  2286. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2287. return Status;
  2288. }
  2289. NTSTATUS
  2290. BowserForEachTransport (
  2291. IN PTRANSPORT_ENUM_ROUTINE Routine,
  2292. IN OUT PVOID Context
  2293. )
  2294. /*++
  2295. Routine Description:
  2296. This routine will enumerate the transports and call back the enum
  2297. routine provided with each transport.
  2298. Arguments:
  2299. Routine - Routine to call for each transport
  2300. Context - Parameter to pass to 'Routine'
  2301. Return Value:
  2302. NTSTATUS - Final status of request.
  2303. --*/
  2304. {
  2305. PLIST_ENTRY TransportEntry, NextEntry;
  2306. PTRANSPORT Transport = NULL;
  2307. PPAGED_TRANSPORT PagedTransport = NULL;
  2308. NTSTATUS Status = STATUS_SUCCESS;
  2309. PAGED_CODE();
  2310. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2311. for (TransportEntry = BowserTransportHead.Flink ;
  2312. TransportEntry != &BowserTransportHead ;
  2313. TransportEntry = NextEntry) {
  2314. PagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
  2315. //
  2316. // Ignore deleted transports.
  2317. //
  2318. if ( PagedTransport->DeletedTransport ) {
  2319. NextEntry = PagedTransport->GlobalNext.Flink;
  2320. continue;
  2321. }
  2322. Transport = PagedTransport->NonPagedTransport;
  2323. dprintf(DPRT_REF, ("Call Reference transport %lx from BowserForEachTransport.\n", Transport));
  2324. BowserReferenceTransport(Transport);
  2325. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2326. Status = (Routine)(Transport, Context);
  2327. if (!NT_SUCCESS(Status)) {
  2328. BowserDereferenceTransport(Transport);
  2329. return Status;
  2330. }
  2331. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2332. NextEntry = PagedTransport->GlobalNext.Flink;
  2333. BowserDereferenceTransport(Transport);
  2334. }
  2335. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2336. return Status;
  2337. }
  2338. NTSTATUS
  2339. BowserForEachTransportName(
  2340. IN PTRANSPORT Transport,
  2341. IN PTRANSPORT_NAME_ENUM_ROUTINE Routine,
  2342. IN OUT PVOID Context
  2343. )
  2344. /*++
  2345. Routine Description:
  2346. This routine will enumerate the names associated with a transport
  2347. and call back the enum routine provided with each transport name.
  2348. Arguments:
  2349. Return Value:
  2350. NTSTATUS - Final status of request.
  2351. --*/
  2352. {
  2353. PLIST_ENTRY TransportEntry, NextEntry;
  2354. PTRANSPORT_NAME TransportName = NULL;
  2355. PPAGED_TRANSPORT_NAME PagedTransportName = NULL;
  2356. NTSTATUS Status = STATUS_SUCCESS;
  2357. PAGED_CODE();
  2358. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2359. try {
  2360. for (TransportEntry = Transport->PagedTransport->NameChain.Flink ;
  2361. TransportEntry &&
  2362. (TransportEntry != &Transport->PagedTransport->NameChain) ;
  2363. TransportEntry = NextEntry) {
  2364. PagedTransportName = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT_NAME, TransportNext);
  2365. TransportName = PagedTransportName->NonPagedTransportName;
  2366. BowserReferenceTransportName( TransportName );
  2367. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2368. Status = (Routine)(TransportName, Context);
  2369. if (!NT_SUCCESS(Status)) {
  2370. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2371. BowserDereferenceTransportName( TransportName );
  2372. try_return(Status);
  2373. }
  2374. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2375. NextEntry = PagedTransportName->TransportNext.Flink;
  2376. BowserDereferenceTransportName( TransportName );
  2377. }
  2378. try_exit:NOTHING;
  2379. } finally {
  2380. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2381. }
  2382. return Status;
  2383. }
  2384. NTSTATUS
  2385. BowserDeleteTransportNameByName(
  2386. IN PTRANSPORT Transport,
  2387. IN PUNICODE_STRING Name OPTIONAL,
  2388. IN DGRECEIVER_NAME_TYPE NameType
  2389. )
  2390. /*++
  2391. Routine Description:
  2392. This routine deletes a transport name associated with a specific network.
  2393. Arguments:
  2394. Transport - Specifies the transport on which to delete the name.
  2395. Name - Specifies the transport name to delete.
  2396. If not specified, all names of the specified name type are deleted.
  2397. NameType - Specifies the name type of the name.
  2398. Return Value:
  2399. NTSTATUS - Final status of request.
  2400. --*/
  2401. {
  2402. PLIST_ENTRY TransportEntry, NextEntry;
  2403. PTRANSPORT_NAME TransportName = NULL;
  2404. PPAGED_TRANSPORT_NAME PagedTransportName = NULL;
  2405. NTSTATUS Status = STATUS_SUCCESS;
  2406. PAGED_CODE();
  2407. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2408. try {
  2409. for (TransportEntry = Transport->PagedTransport->NameChain.Flink ;
  2410. TransportEntry != &Transport->PagedTransport->NameChain ;
  2411. TransportEntry = NextEntry) {
  2412. PagedTransportName = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT_NAME, TransportNext);
  2413. TransportName = PagedTransportName->NonPagedTransportName;
  2414. ASSERT (TransportName->NameType == PagedTransportName->Name->NameType);
  2415. if ((TransportName->NameType == NameType) &&
  2416. (Name == NULL ||
  2417. Name->Length == 0 ||
  2418. RtlEqualUnicodeString(&PagedTransportName->Name->Name, Name, TRUE))) {
  2419. NextEntry = TransportEntry->Flink;
  2420. //
  2421. // Remove the TransportName from the list of transport names for
  2422. // this transport.
  2423. //
  2424. ASSERT( PagedTransportName->TransportNext.Flink != NULL);
  2425. RemoveEntryList(&PagedTransportName->TransportNext);
  2426. PagedTransportName->TransportNext.Flink = NULL;
  2427. PagedTransportName->TransportNext.Blink = NULL;
  2428. //
  2429. // Since we delinked it, we need to dereference it.
  2430. //
  2431. Status = BowserDereferenceTransportName(TransportName);
  2432. if (!NT_SUCCESS(Status)) {
  2433. try_return(Status);
  2434. }
  2435. } else {
  2436. NextEntry = PagedTransportName->TransportNext.Flink;
  2437. }
  2438. }
  2439. try_exit:NOTHING;
  2440. } finally {
  2441. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2442. }
  2443. return Status;
  2444. }
  2445. NTSTATUS
  2446. BowserSubmitTdiRequest (
  2447. IN PFILE_OBJECT FileObject,
  2448. IN PIRP Irp
  2449. )
  2450. /*++
  2451. Routine Description:
  2452. This routine submits a request to TDI and waits for it to complete.
  2453. Arguments:
  2454. IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
  2455. IN PIRP Irp - TDI request to submit.
  2456. Return Value:
  2457. NTSTATUS - Final status of request.
  2458. --*/
  2459. {
  2460. KEVENT Event;
  2461. NTSTATUS Status;
  2462. PAGED_CODE();
  2463. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  2464. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  2465. IoSetCompletionRoutine(Irp, BowserCompleteTdiRequest, &Event, TRUE, TRUE, TRUE);
  2466. //
  2467. // Submit the disconnect request
  2468. //
  2469. Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
  2470. //
  2471. // If it failed immediately, return now, otherwise wait.
  2472. //
  2473. if (!NT_SUCCESS(Status)) {
  2474. dlog(DPRT_TDI, ("BowserSubmitTdiRequest: submit request. Status = %X", Status));
  2475. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  2476. return Status;
  2477. }
  2478. if (Status == STATUS_PENDING) {
  2479. dlog(DPRT_TDI, ("TDI request issued, waiting..."));
  2480. Status = KeWaitForSingleObject(&Event, // Object to wait on.
  2481. Executive, // Reason for waiting
  2482. KernelMode, // Processor mode
  2483. FALSE, // Alertable
  2484. NULL); // Timeout
  2485. if (!NT_SUCCESS(Status)) {
  2486. dlog(DPRT_TDI, ("Could not wait for operation to complete"));
  2487. KeBugCheck( 666 );
  2488. }
  2489. Status = Irp->IoStatus.Status;
  2490. }
  2491. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  2492. dlog(DPRT_TDI, ("TDI request complete\n"));
  2493. return(Status);
  2494. }
  2495. NTSTATUS
  2496. BowserCompleteTdiRequest (
  2497. IN PDEVICE_OBJECT DeviceObject,
  2498. IN PIRP Irp,
  2499. IN PVOID Context
  2500. )
  2501. /*++
  2502. Routine Description:
  2503. Completion routine for SubmitTdiRequest operation.
  2504. Arguments:
  2505. IN PDEVICE_OBJECT DeviceObject, - Supplies a pointer to the device object
  2506. IN PIRP Irp, - Supplies the IRP submitted
  2507. IN PVOID Context - Supplies a pointer to the kernel event to release
  2508. Return Value:
  2509. NTSTATUS - Status of KeSetEvent
  2510. We return STATUS_MORE_PROCESSING_REQUIRED to prevent the IRP completion
  2511. code from processing this puppy any more.
  2512. --*/
  2513. {
  2514. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  2515. dprintf(DPRT_TDI, ("CompleteTdiRequest: %lx\n", Context));
  2516. //
  2517. // Set the event to the Signalled state with 0 priority increment and
  2518. // indicate that we will not be blocking soon.
  2519. //
  2520. KeSetEvent((PKEVENT )Context, 0, FALSE);
  2521. return STATUS_MORE_PROCESSING_REQUIRED;
  2522. // Quiet the compiler.
  2523. if (Irp || DeviceObject){};
  2524. }
  2525. typedef struct _SEND_DATAGRAM_CONTEXT {
  2526. PTDI_CONNECTION_INFORMATION ConnectionInformation;
  2527. PVOID Header;
  2528. BOOLEAN WaitForCompletion;
  2529. KEVENT Event;
  2530. } SEND_DATAGRAM_CONTEXT, *PSEND_DATAGRAM_CONTEXT;
  2531. NTSTATUS
  2532. BowserSendDatagram (
  2533. IN PTRANSPORT Transport,
  2534. IN PUNICODE_STRING Domain OPTIONAL,
  2535. IN DGRECEIVER_NAME_TYPE NameType,
  2536. IN PVOID Buffer,
  2537. IN ULONG BufferLength,
  2538. IN BOOLEAN WaitForCompletion,
  2539. IN PSTRING DestinationAddress OPTIONAL,
  2540. IN BOOLEAN IsHostAnnouncement
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. This routine sends a datagram to the specified domain.
  2545. Arguments:
  2546. Domain - the name of the domain to send to.
  2547. Please note that the DOMAIN is padded with spaces and
  2548. terminated with the appropriate signature byte (00 or 07).
  2549. Buffer - the message to send.
  2550. BufferLength - the length of the buffer,
  2551. IsHostAnnouncement - True if the datagram is a host announcement
  2552. Return Value:
  2553. NTSTATUS - results of operation.
  2554. --*/
  2555. {
  2556. NTSTATUS Status = STATUS_SUCCESS;
  2557. ULONG connectionInformationSize;
  2558. PIRP irp = NULL;
  2559. PMDL mdlAddress = NULL;
  2560. PSEND_DATAGRAM_CONTEXT context = NULL;
  2561. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  2562. // PTRANSPORT_NAME TComputerName;
  2563. ANSI_STRING AnsiString;
  2564. UCHAR IpxPacketType;
  2565. PFILE_OBJECT FileObject = NULL;
  2566. PDEVICE_OBJECT DeviceObject;
  2567. PVOID pBuffToFree = Buffer;
  2568. PAGED_CODE();
  2569. //
  2570. // Ensure the computername has been registered for this transport
  2571. //
  2572. if ( Transport->ComputerName == NULL ) {
  2573. Status = STATUS_BAD_NETWORK_PATH;
  2574. goto Cleanup;
  2575. }
  2576. //
  2577. // Ensure the Device and File object are known.
  2578. //
  2579. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  2580. if (!FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
  2581. DeviceObject = Transport->ComputerName->DeviceObject;
  2582. FileObject = Transport->ComputerName->FileObject;
  2583. } else {
  2584. DeviceObject = Transport->IpxSocketDeviceObject;
  2585. FileObject = Transport->IpxSocketFileObject;
  2586. }
  2587. if ( DeviceObject == NULL || FileObject == NULL ) {
  2588. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2589. Status = STATUS_BAD_NETWORK_PATH;
  2590. goto Cleanup;
  2591. }
  2592. if ( FileObject != NULL ) {
  2593. ObReferenceObject( FileObject );
  2594. }
  2595. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  2596. //
  2597. // Allocate a context describing this datagram send.
  2598. //
  2599. context = ALLOCATE_POOL(NonPagedPool, sizeof(SEND_DATAGRAM_CONTEXT), POOL_SENDDATAGRAM);
  2600. if ( context == NULL) {
  2601. Status = STATUS_NO_MEMORY;
  2602. goto Cleanup;
  2603. }
  2604. context->Header = NULL;
  2605. context->ConnectionInformation = NULL;
  2606. connectionInformationSize = sizeof(TDI_CONNECTION_INFORMATION) +
  2607. max(sizeof(TA_NETBIOS_EX_ADDRESS),
  2608. sizeof(TA_IPX_ADDRESS));
  2609. if (Domain == NULL) {
  2610. Domain = &Transport->DomainInfo->DomUnicodeDomainName;
  2611. }
  2612. if (FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
  2613. PSMB_IPX_NAME_PACKET NamePacket;
  2614. OEM_STRING NetBiosName;
  2615. context->Header = ALLOCATE_POOL(NonPagedPool, BufferLength + sizeof(SMB_IPX_NAME_PACKET), POOL_SENDDATAGRAM);
  2616. if ( context->Header == NULL ) {
  2617. Status = STATUS_INSUFFICIENT_RESOURCES;
  2618. goto Cleanup;
  2619. }
  2620. NamePacket = context->Header;
  2621. RtlZeroMemory(NamePacket->Route, sizeof(NamePacket->Route));
  2622. NamePacket->Operation = SMB_IPX_MAILSLOT_SEND;
  2623. switch (NameType) {
  2624. case BrowserElection:
  2625. if ( IsHostAnnouncement ) {
  2626. NamePacket->NameType = SMB_IPX_NAME_TYPE_BROWSER;
  2627. } else {
  2628. NamePacket->NameType = SMB_IPX_NAME_TYPE_WORKKGROUP;
  2629. }
  2630. break;
  2631. case ComputerName:
  2632. case AlternateComputerName:
  2633. NamePacket->NameType = SMB_IPX_NAME_TYPE_MACHINE;
  2634. break;
  2635. case MasterBrowser:
  2636. NamePacket->NameType = SMB_IPX_NAME_TYPE_WORKKGROUP;
  2637. break;
  2638. //
  2639. // Don't send on name types that direct host IPX can't handle.
  2640. //
  2641. // Domain(1B): Direct host IPX datagram receivers aren't particular
  2642. // about the 16th byte of the netbios name. Therefore, all of them
  2643. // accept a Domain<1B> datagram. However, such sends are destined
  2644. // only to the PDC.
  2645. //
  2646. // Domain(1C): Domain(1C) is registered only by NT DCs. However,
  2647. // NT DCs don't completely support direct host IPX. But they do
  2648. // completely support NwLnkNb.
  2649. //
  2650. // We silently ingore these errors allowing the caller to duplicate
  2651. // the send on NwLnkNb.
  2652. case PrimaryDomainBrowser:
  2653. case DomainName:
  2654. Status = STATUS_SUCCESS;
  2655. goto Cleanup;
  2656. //
  2657. // Fail on sends to non-sensical name types.
  2658. //
  2659. // DomainAnnouncements aren't sent separately.
  2660. //
  2661. default:
  2662. // Silently ignore the
  2663. Status = STATUS_INVALID_DEVICE_REQUEST;
  2664. goto Cleanup;
  2665. }
  2666. NamePacket->MessageId = 0;
  2667. NetBiosName.Length = 0;
  2668. NetBiosName.MaximumLength = SMB_IPX_NAME_LENGTH;
  2669. NetBiosName.Buffer = NamePacket->Name;
  2670. Status = RtlUpcaseUnicodeStringToOemString(&NetBiosName, Domain, FALSE);
  2671. if (!NT_SUCCESS(Status)) {
  2672. goto Cleanup;
  2673. }
  2674. RtlCopyMemory(&NetBiosName.Buffer[NetBiosName.Length], " ",
  2675. SMB_IPX_NAME_LENGTH-NetBiosName.Length);
  2676. NamePacket->Name[SMB_IPX_NAME_LENGTH-1] = WORKSTATION_SIGNATURE;
  2677. RtlCopyMemory(NamePacket->SourceName, ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName, SMB_IPX_NAME_LENGTH);
  2678. RtlCopyMemory((NamePacket+1), Buffer, BufferLength);
  2679. // Replace Buffer w/ IPX modified one.
  2680. // - ensure cleanup will free input Buffer.
  2681. ASSERT(Buffer == pBuffToFree);
  2682. FREE_POOL(Buffer);
  2683. pBuffToFree = NULL; // cleanup will free context->Header
  2684. Buffer = context->Header;
  2685. BufferLength += sizeof(SMB_IPX_NAME_PACKET);
  2686. } else {
  2687. // ensure consistency
  2688. ASSERT(Buffer == pBuffToFree);
  2689. context->Header = Buffer;
  2690. pBuffToFree = NULL; // don't cleanup for async case.
  2691. }
  2692. context->ConnectionInformation = ALLOCATE_POOL(NonPagedPool,
  2693. connectionInformationSize, POOL_CONNECTINFO
  2694. );
  2695. if ( context->ConnectionInformation == NULL ) {
  2696. Status = STATUS_INSUFFICIENT_RESOURCES;
  2697. goto Cleanup;
  2698. }
  2699. context->ConnectionInformation->UserDataLength = 0;
  2700. context->ConnectionInformation->UserData = NULL;
  2701. context->ConnectionInformation->OptionsLength = 0;
  2702. context->ConnectionInformation->Options = NULL;
  2703. AnsiString.Buffer = (PCHAR)(context->ConnectionInformation + 1);
  2704. AnsiString.MaximumLength = (USHORT)(connectionInformationSize - sizeof(TDI_CONNECTION_INFORMATION));
  2705. context->ConnectionInformation->RemoteAddress = AnsiString.Buffer;
  2706. context->WaitForCompletion = WaitForCompletion;
  2707. // ComputerName = Transport->ComputerName;
  2708. if (!ARGUMENT_PRESENT(DestinationAddress)) {
  2709. //
  2710. // If this is for our primary domain, and the request is destined
  2711. // for the master browser name, then stick in the address of our
  2712. // master browser if we know it.
  2713. //
  2714. if ((RtlCompareMemory(Domain->Buffer, ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName, SMB_IPX_NAME_LENGTH) == SMB_IPX_NAME_LENGTH) &&
  2715. ( NameType == MasterBrowser ) &&
  2716. (Transport->PagedTransport->MasterBrowserAddress.Length != 0) ) {
  2717. //
  2718. // This is for our domain. If it's for our master browser
  2719. // and we know who that is, we're done - copy over the master's address
  2720. // and send it.
  2721. //
  2722. ASSERT (Transport->PagedTransport->MasterBrowserAddress.Length == sizeof(TA_IPX_ADDRESS));
  2723. RtlCopyMemory(context->ConnectionInformation->RemoteAddress,
  2724. Transport->PagedTransport->MasterBrowserAddress.Buffer,
  2725. Transport->PagedTransport->MasterBrowserAddress.Length);
  2726. //
  2727. // This is a directed packet, don't broadcast it.
  2728. //
  2729. IpxPacketType = IPX_DIRECTED_PACKET;
  2730. context->ConnectionInformation->OptionsLength = sizeof(IpxPacketType);
  2731. context->ConnectionInformation->Options = &IpxPacketType;
  2732. } else if (FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
  2733. PTA_IPX_ADDRESS IpxAddress = (PTA_IPX_ADDRESS)AnsiString.Buffer;
  2734. IpxAddress->TAAddressCount = 1;
  2735. IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  2736. IpxAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IPX;
  2737. IpxAddress->Address[0].Address[0].NetworkAddress = 0;
  2738. IpxAddress->Address[0].Address[0].NodeAddress[0] = 0xff;
  2739. IpxAddress->Address[0].Address[0].NodeAddress[1] = 0xff;
  2740. IpxAddress->Address[0].Address[0].NodeAddress[2] = 0xff;
  2741. IpxAddress->Address[0].Address[0].NodeAddress[3] = 0xff;
  2742. IpxAddress->Address[0].Address[0].NodeAddress[4] = 0xff;
  2743. IpxAddress->Address[0].Address[0].NodeAddress[5] = 0xff;
  2744. IpxAddress->Address[0].Address[0].Socket = SMB_IPX_MAILSLOT_SOCKET;
  2745. } else {
  2746. Status = BowserBuildTransportAddress(&AnsiString,
  2747. Domain,
  2748. NameType,
  2749. Transport);
  2750. if (!NT_SUCCESS(Status)) {
  2751. goto Cleanup;
  2752. }
  2753. context->ConnectionInformation->RemoteAddressLength = AnsiString.Length;
  2754. }
  2755. } else {
  2756. //
  2757. // This is already correctly formatted, so just put it on the wire.
  2758. //
  2759. RtlCopyMemory(context->ConnectionInformation->RemoteAddress, DestinationAddress->Buffer, DestinationAddress->Length);
  2760. context->ConnectionInformation->RemoteAddressLength = DestinationAddress->Length;
  2761. //
  2762. // This is a directed packet, don't broadcast it.
  2763. //
  2764. IpxPacketType = IPX_DIRECTED_PACKET;
  2765. context->ConnectionInformation->OptionsLength = sizeof(IpxPacketType);
  2766. context->ConnectionInformation->Options = &IpxPacketType;
  2767. }
  2768. irp = IoAllocateIrp( DeviceObject->StackSize, TRUE);
  2769. if (irp == NULL) {
  2770. Status = STATUS_INSUFFICIENT_RESOURCES;
  2771. goto Cleanup;
  2772. }
  2773. mdlAddress = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, NULL);
  2774. if (mdlAddress == NULL) {
  2775. IoFreeIrp(irp);
  2776. Status = STATUS_INSUFFICIENT_RESOURCES;
  2777. goto Cleanup;
  2778. }
  2779. KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
  2780. MmBuildMdlForNonPagedPool(mdlAddress);
  2781. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  2782. ASSERT (KeGetCurrentIrql() == 0);
  2783. TdiBuildSendDatagram( irp,
  2784. DeviceObject,
  2785. FileObject,
  2786. CompleteSendDatagram,
  2787. context,
  2788. mdlAddress,
  2789. BufferLength,
  2790. context->ConnectionInformation);
  2791. Status = IoCallDriver(DeviceObject, irp);
  2792. ASSERT (KeGetCurrentIrql() == 0);
  2793. if (WaitForCompletion) {
  2794. ASSERT (KeGetCurrentIrql() == 0);
  2795. if (Status == STATUS_PENDING) {
  2796. Status = KeWaitForSingleObject(&context->Event,
  2797. Executive,
  2798. KernelMode,
  2799. FALSE,
  2800. NULL);
  2801. }
  2802. IoFreeMdl(irp->MdlAddress);
  2803. //
  2804. // Retrieve the status from the IRP.
  2805. //
  2806. Status = irp->IoStatus.Status;
  2807. IoFreeIrp(irp);
  2808. } else {
  2809. //
  2810. // Let completion routine free the context
  2811. //
  2812. context = NULL;
  2813. }
  2814. ASSERT (KeGetCurrentIrql() == 0);
  2815. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  2816. //
  2817. // Free locally used resources
  2818. //
  2819. Cleanup:
  2820. if ( context != NULL ) {
  2821. if ( context->Header != NULL &&
  2822. context->Header != pBuffToFree ) {
  2823. FREE_POOL( context->Header );
  2824. }
  2825. if (context->ConnectionInformation != NULL ) {
  2826. FREE_POOL(context->ConnectionInformation);
  2827. }
  2828. FREE_POOL(context);
  2829. }
  2830. if (pBuffToFree) {
  2831. FREE_POOL( pBuffToFree );
  2832. }
  2833. if ( FileObject != NULL ) {
  2834. ObDereferenceObject( FileObject );
  2835. }
  2836. return Status;
  2837. } // BowserSendDatagram
  2838. NTSTATUS
  2839. CompleteSendDatagram (
  2840. IN PDEVICE_OBJECT DeviceObject,
  2841. IN PIRP Irp,
  2842. IN PVOID Ctx
  2843. )
  2844. /*++
  2845. Routine Description:
  2846. Completion routine for SubmitTdiRequest operation.
  2847. Arguments:
  2848. IN PDEVICE_OBJECT DeviceObject, - Supplies a pointer to the device object
  2849. IN PIRP Irp, - Supplies the IRP submitted
  2850. IN PVOID Context - Supplies a pointer to the kernel event to release
  2851. Return Value:
  2852. NTSTATUS - Status of KeSetEvent
  2853. We return STATUS_MORE_PROCESSING_REQUIRED to prevent the IRP completion
  2854. code from processing this puppy any more.
  2855. --*/
  2856. {
  2857. PSEND_DATAGRAM_CONTEXT Context = Ctx;
  2858. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  2859. dprintf(DPRT_TDI, ("CompleteTdiRequest: %lx\n", Context));
  2860. if (Context->WaitForCompletion) {
  2861. //
  2862. // Set the event to the Signalled state with 0 priority increment and
  2863. // indicate that we will not be blocking soon.
  2864. //
  2865. KeSetEvent(&Context->Event, 0, FALSE);
  2866. } else {
  2867. FREE_POOL(Context->ConnectionInformation);
  2868. FREE_POOL(Context->Header);
  2869. FREE_POOL(Context);
  2870. IoFreeMdl(Irp->MdlAddress);
  2871. IoFreeIrp(Irp);
  2872. }
  2873. return STATUS_MORE_PROCESSING_REQUIRED;
  2874. UNREFERENCED_PARAMETER(DeviceObject);
  2875. }
  2876. NTSTATUS
  2877. BowserSendSecondClassMailslot (
  2878. IN PTRANSPORT Transport,
  2879. IN PUNICODE_STRING Domain OPTIONAL,
  2880. IN DGRECEIVER_NAME_TYPE NameType,
  2881. IN PVOID Message,
  2882. IN ULONG MessageLength,
  2883. IN BOOLEAN WaitForCompletion,
  2884. IN PCHAR mailslotNameData,
  2885. IN PSTRING DestinationAddress OPTIONAL
  2886. )
  2887. {
  2888. ULONG dataSize;
  2889. ULONG transactionDataSize;
  2890. ULONG smbSize;
  2891. PSMB_HEADER header;
  2892. PSMB_TRANSACT_MAILSLOT parameters;
  2893. PSZ mailslotName;
  2894. ULONG mailslotNameLength;
  2895. PSZ domainInData;
  2896. PVOID message;
  2897. NTSTATUS status;
  2898. PAGED_CODE();
  2899. //
  2900. // Determine the sizes of various fields that will go in the SMB
  2901. // and the total size of the SMB.
  2902. //
  2903. mailslotNameLength = strlen( mailslotNameData );
  2904. transactionDataSize = MessageLength;
  2905. dataSize = mailslotNameLength + 1 + transactionDataSize;
  2906. smbSize = sizeof(SMB_HEADER) + sizeof(SMB_TRANSACT_MAILSLOT) - 1 + dataSize;
  2907. header = ALLOCATE_POOL( NonPagedPool, smbSize, POOL_MAILSLOT_HEADER );
  2908. if ( header == NULL ) {
  2909. return STATUS_INSUFFICIENT_RESOURCES;
  2910. }
  2911. //
  2912. // Fill in the header. Most of the fields don't matter and are
  2913. // zeroed.
  2914. //
  2915. RtlZeroMemory( header, smbSize );
  2916. header->Protocol[0] = 0xFF;
  2917. header->Protocol[1] = 'S';
  2918. header->Protocol[2] = 'M';
  2919. header->Protocol[3] = 'B';
  2920. header->Command = SMB_COM_TRANSACTION;
  2921. //
  2922. // Get the pointer to the params and fill them in.
  2923. //
  2924. parameters = (PSMB_TRANSACT_MAILSLOT)( header + 1 );
  2925. mailslotName = (PSZ)( parameters + 1 ) - 1;
  2926. domainInData = mailslotName + mailslotNameLength + 1;
  2927. message = domainInData;
  2928. parameters->WordCount = 0x11;
  2929. SmbPutUshort( &parameters->TotalDataCount, (USHORT)transactionDataSize );
  2930. SmbPutUlong( &parameters->Timeout, 0x3E8 ); // !!! fix
  2931. SmbPutUshort( &parameters->DataCount, (USHORT)transactionDataSize );
  2932. SmbPutUshort(
  2933. &parameters->DataOffset,
  2934. (USHORT)( (ULONG_PTR)message - (ULONG_PTR)header )
  2935. );
  2936. parameters->SetupWordCount = 3;
  2937. SmbPutUshort( &parameters->Opcode, MS_WRITE_OPCODE );
  2938. SmbPutUshort( &parameters->Priority, 1);
  2939. SmbPutUshort( &parameters->Class, 2 );
  2940. SmbPutUshort( &parameters->ByteCount, (USHORT)dataSize );
  2941. RtlCopyMemory( mailslotName, mailslotNameData, mailslotNameLength + 1 );
  2942. RtlCopyMemory( message, Message, MessageLength );
  2943. //
  2944. // Send the actual mailslot message.
  2945. //
  2946. status = BowserSendDatagram( Transport,
  2947. Domain,
  2948. NameType,
  2949. header,
  2950. smbSize,
  2951. WaitForCompletion,
  2952. DestinationAddress,
  2953. (BOOLEAN)(((PHOST_ANNOUNCE_PACKET)Message)->AnnounceType == LocalMasterAnnouncement) );
  2954. return status;
  2955. } // BowserSendSecondClassMailslot
  2956. NTSTATUS
  2957. BowserSendRequestAnnouncement(
  2958. IN PUNICODE_STRING DestinationName,
  2959. IN DGRECEIVER_NAME_TYPE NameType,
  2960. IN PTRANSPORT Transport
  2961. )
  2962. {
  2963. REQUEST_ANNOUNCE_PACKET AnnounceRequest;
  2964. ULONG AnnouncementRequestLength;
  2965. NTSTATUS Status;
  2966. PAGED_CODE();
  2967. //
  2968. // If we don't
  2969. AnnounceRequest.Type = AnnouncementRequest;
  2970. AnnounceRequest.RequestAnnouncement.Flags = 0;
  2971. strcpy( AnnounceRequest.RequestAnnouncement.Reply,
  2972. Transport->DomainInfo->DomOemComputerName.Buffer );
  2973. AnnouncementRequestLength = FIELD_OFFSET(REQUEST_ANNOUNCE_PACKET, RequestAnnouncement.Reply) +
  2974. Transport->DomainInfo->DomOemComputerName.Length + 1;
  2975. Status = BowserSendSecondClassMailslot(Transport,
  2976. DestinationName,
  2977. NameType,
  2978. &AnnounceRequest,
  2979. AnnouncementRequestLength,
  2980. TRUE,
  2981. MAILSLOT_BROWSER_NAME,
  2982. NULL);
  2983. return Status;
  2984. }
  2985. VOID
  2986. BowserpInitializeTdi (
  2987. VOID
  2988. )
  2989. /*++
  2990. Routine Description:
  2991. This routine initializes the global variables used in the transport
  2992. package.
  2993. Arguments:
  2994. None.
  2995. Return Value:
  2996. None.
  2997. --*/
  2998. {
  2999. //
  3000. // Initialize the Transport list chain
  3001. //
  3002. InitializeListHead(&BowserTransportHead);
  3003. ExInitializeResourceLite(&BowserTransportDatabaseResource);
  3004. KeInitializeSpinLock(&BowserTransportMasterNameSpinLock);
  3005. BowserInitializeDomains();
  3006. }
  3007. VOID
  3008. BowserpUninitializeTdi (
  3009. VOID
  3010. )
  3011. /*++
  3012. Routine Description:
  3013. This routine initializes the global variables used in the transport
  3014. package.
  3015. Arguments:
  3016. None.
  3017. Return Value:
  3018. None.
  3019. --*/
  3020. {
  3021. PAGED_CODE();
  3022. ASSERT (IsListEmpty(&BowserTransportHead));
  3023. ExDeleteResourceLite(&BowserTransportDatabaseResource);
  3024. }