Windows NT 4.0 source code leak
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.

3618 lines
94 KiB

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