3619 lines
94 KiB
C
3619 lines
94 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
bowtdi.c
|
||
|
||
Abstract:
|
||
|
||
This module implements all of the routines that interface with the TDI
|
||
transport for NT
|
||
|
||
Author:
|
||
|
||
Larry Osterman (LarryO) 21-Jun-1990
|
||
|
||
Revision History:
|
||
|
||
21-Jun-1990 LarryO
|
||
|
||
Created
|
||
|
||
--*/
|
||
|
||
|
||
#include "precomp.h"
|
||
#include <isnkrnl.h>
|
||
#include <smbipx.h>
|
||
#include <nbtioctl.h>
|
||
#pragma hdrstop
|
||
|
||
typedef struct _ENUM_TRANSPORTS_CONTEXT {
|
||
PVOID OutputBuffer;
|
||
PVOID OutputBufferEnd;
|
||
PVOID LastOutputBuffer; // Points to the last entry in the list.
|
||
ULONG OutputBufferSize;
|
||
ULONG EntriesRead;
|
||
ULONG TotalEntries;
|
||
ULONG TotalBytesNeeded;
|
||
ULONG OutputBufferDisplacement;
|
||
} ENUM_TRANSPORTS_CONTEXT, *PENUM_TRANSPORTS_CONTEXT;
|
||
|
||
NTSTATUS
|
||
EnumerateTransportsWorker(
|
||
IN PTRANSPORT Transport,
|
||
IN OUT PVOID Ctx
|
||
);
|
||
|
||
ERESOURCE
|
||
BowserTransportDatabaseResource = {0};
|
||
|
||
//
|
||
//
|
||
// Forward definitions of local routines.
|
||
//
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserpTdiSetEventHandler (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PFILE_OBJECT FileObject,
|
||
IN ULONG EventType,
|
||
IN PVOID EventHandler,
|
||
IN PVOID TransportName
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
BowserDetermineProviderInformation(
|
||
IN PUNICODE_STRING TransportName,
|
||
OUT PTDI_PROVIDER_INFO ProviderInfo,
|
||
OUT PULONG IpSubnetNumber
|
||
);
|
||
|
||
NTSTATUS
|
||
UnbindTransportWorker(
|
||
IN PTRANSPORT Transport,
|
||
IN OUT PVOID Ctx
|
||
);
|
||
|
||
NTSTATUS
|
||
BowserpTdiRemoveAddresses(
|
||
IN PTRANSPORT Transport
|
||
);
|
||
|
||
|
||
VOID
|
||
BowserpFreeTransport(
|
||
IN PTRANSPORT Transport
|
||
);
|
||
|
||
VOID
|
||
BowserDeleteTransport(
|
||
IN PTRANSPORT Transport
|
||
);
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserSubmitTdiRequest (
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
BowserCompleteTdiRequest (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
CompleteSendDatagram (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Ctx
|
||
);
|
||
|
||
NTSTATUS
|
||
BowserEnableIpxDatagramSocket(
|
||
IN PTRANSPORT Transport
|
||
);
|
||
|
||
NTSTATUS
|
||
BowserOpenNetbiosAddress(
|
||
IN PPAGED_TRANSPORT_NAME PagedTransportName,
|
||
IN PTRANSPORT Transport,
|
||
IN PBOWSER_NAME Name
|
||
);
|
||
|
||
VOID
|
||
BowserCloseNetbiosAddress(
|
||
IN PTRANSPORT_NAME TransportName
|
||
);
|
||
|
||
VOID
|
||
BowserCloseAllNetbiosAddresses(
|
||
IN PTRANSPORT Transport
|
||
);
|
||
|
||
NTSTATUS
|
||
BowserSendDatagram (
|
||
IN PTRANSPORT Transport,
|
||
IN PVOID RecipientAddress,
|
||
IN DGRECEIVER_NAME_TYPE NameType,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferLength,
|
||
IN BOOLEAN WaitForCompletion,
|
||
IN PSTRING DestinationAddress OPTIONAL,
|
||
IN BOOLEAN IsHostAnnouncment
|
||
);
|
||
|
||
NTSTATUS
|
||
OpenIpxSocket (
|
||
OUT PHANDLE Handle,
|
||
OUT PFILE_OBJECT *FileObject,
|
||
OUT PDEVICE_OBJECT *DeviceObject,
|
||
IN PUNICODE_STRING DeviceName,
|
||
IN USHORT Socket
|
||
);
|
||
|
||
NTSTATUS
|
||
BowserIssueTdiAction (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PVOID Action,
|
||
IN ULONG ActionSize
|
||
);
|
||
|
||
NTSTATUS
|
||
GetNetworkAddress (
|
||
IN PTRANSPORT_NAME TransportName
|
||
);
|
||
|
||
NTSTATUS
|
||
BowserIssueTdiQuery(
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PCHAR Buffer,
|
||
IN ULONG BufferSize,
|
||
IN USHORT QueryType
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, BowserTdiAllocateTransport)
|
||
#pragma alloc_text(PAGE, BowserUnbindFromAllTransports)
|
||
#pragma alloc_text(PAGE, UnbindTransportWorker)
|
||
#pragma alloc_text(PAGE, BowserFreeTransportByName)
|
||
#pragma alloc_text(PAGE, BowserEnumerateTransports)
|
||
#pragma alloc_text(PAGE, EnumerateTransportsWorker)
|
||
#pragma alloc_text(PAGE, BowserDereferenceTransport)
|
||
#pragma alloc_text(PAGE, BowserCreateTransportName)
|
||
#pragma alloc_text(PAGE, BowserpTdiRemoveAddresses)
|
||
#pragma alloc_text(PAGE, BowserFindTransportName)
|
||
#pragma alloc_text(PAGE, BowserFreeTransportName)
|
||
#pragma alloc_text(PAGE, BowserDeleteTransport)
|
||
#pragma alloc_text(PAGE, BowserpFreeTransport)
|
||
#pragma alloc_text(PAGE, BowserpTdiSetEventHandler)
|
||
#pragma alloc_text(PAGE, BowserBuildTransportAddress)
|
||
#pragma alloc_text(PAGE, BowserUpdateProviderInformation)
|
||
#pragma alloc_text(PAGE, BowserDetermineProviderInformation)
|
||
#pragma alloc_text(PAGE, BowserFindTransport)
|
||
#pragma alloc_text(PAGE, BowserForEachTransport)
|
||
#pragma alloc_text(PAGE, BowserForEachTransportName)
|
||
#pragma alloc_text(PAGE, BowserDeleteTransportNameByName)
|
||
#pragma alloc_text(PAGE, BowserSubmitTdiRequest)
|
||
#pragma alloc_text(PAGE, BowserSendDatagram)
|
||
#pragma alloc_text(PAGE, BowserSendSecondClassMailslot)
|
||
#pragma alloc_text(PAGE, BowserSendRequestAnnouncement)
|
||
#pragma alloc_text(INIT, BowserpInitializeTdi)
|
||
#pragma alloc_text(PAGE, BowserpUninitializeTdi)
|
||
#pragma alloc_text(PAGE, BowserDereferenceTransportName)
|
||
#pragma alloc_text(PAGE, BowserEnableIpxDatagramSocket)
|
||
#pragma alloc_text(PAGE, BowserOpenNetbiosAddress)
|
||
#pragma alloc_text(PAGE, BowserCloseNetbiosAddress)
|
||
#pragma alloc_text(PAGE, BowserCloseAllNetbiosAddresses)
|
||
#pragma alloc_text(PAGE, OpenIpxSocket)
|
||
#pragma alloc_text(PAGE, BowserIssueTdiAction)
|
||
#pragma alloc_text(PAGE, BowserIssueTdiQuery)
|
||
|
||
#pragma alloc_text(PAGE4BROW, BowserCompleteTdiRequest)
|
||
#pragma alloc_text(PAGE4BROW, CompleteSendDatagram)
|
||
#endif
|
||
|
||
//
|
||
// Flag to indicate that a network isn't an IP network
|
||
//
|
||
#define BOWSER_NON_IP_SUBNET 0xFFFFFFFF
|
||
|
||
|
||
NTSTATUS
|
||
BowserTdiAllocateTransport (
|
||
PUNICODE_STRING TransportName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will allocate a transport descriptor and bind the bowser
|
||
to the transport.
|
||
|
||
Arguments:
|
||
|
||
PUNICODE_STRING TransportName - Supplies the name of the transport provider
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PTRANSPORT NewTransport;
|
||
BOOLEAN NameResourceAcquired = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
// DbgBreakPoint();
|
||
|
||
dprintf(DPRT_TDI, ("BowserTdiAllocateTransport: %wZ\n", TransportName));
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
|
||
NewTransport = BowserFindTransport(TransportName);
|
||
|
||
if (NewTransport == NULL) {
|
||
PLIST_ENTRY NameEntry;
|
||
PPAGED_TRANSPORT PagedTransport = NULL;
|
||
|
||
NewTransport = ALLOCATE_POOL(NonPagedPool, sizeof(TRANSPORT), POOL_TRANSPORT);
|
||
|
||
if (NewTransport == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
RtlZeroMemory( NewTransport, sizeof(TRANSPORT) );
|
||
|
||
PagedTransport = NewTransport->PagedTransport = ALLOCATE_POOL(PagedPool,
|
||
sizeof(PAGED_TRANSPORT) +
|
||
max(sizeof(TA_IPX_ADDRESS),
|
||
sizeof(TA_NETBIOS_ADDRESS)), POOL_PAGED_TRANSPORT);
|
||
|
||
if (NewTransport->PagedTransport == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
RtlZeroMemory( PagedTransport, sizeof(PAGED_TRANSPORT) +
|
||
max(sizeof(TA_IPX_ADDRESS),
|
||
sizeof(TA_NETBIOS_ADDRESS)) );
|
||
|
||
PagedTransport->NonPagedTransport = NewTransport;
|
||
PagedTransport->NumberOfServersInTable = 0;
|
||
|
||
NewTransport->Signature = STRUCTURE_SIGNATURE_TRANSPORT;
|
||
|
||
NewTransport->Size = sizeof(TRANSPORT);
|
||
|
||
PagedTransport->Signature = STRUCTURE_SIGNATURE_PAGED_TRANSPORT;
|
||
PagedTransport->Size = sizeof(PAGED_TRANSPORT);
|
||
|
||
NewTransport->ReferenceCount = 1;
|
||
|
||
ExInitializeResource(&NewTransport->BrowserServerListResource);
|
||
|
||
NewTransport->BrowserServerListToken = 0;
|
||
|
||
NewTransport->BowserBackupList = NULL;
|
||
|
||
NewTransport->IpxSocketFileObject = NULL;
|
||
NewTransport->IpxSocketDeviceObject = NULL;
|
||
|
||
KeInitializeEvent(&NewTransport->GetBackupListComplete, NotificationEvent, TRUE);
|
||
|
||
ExInitializeResource(&NewTransport->Lock);
|
||
|
||
BowserInitializeIrpQueue(&NewTransport->BecomeBackupQueue);
|
||
|
||
BowserInitializeIrpQueue(&NewTransport->BecomeMasterQueue);
|
||
|
||
BowserInitializeIrpQueue(&NewTransport->FindMasterQueue);
|
||
|
||
BowserInitializeIrpQueue(&NewTransport->WaitForMasterAnnounceQueue);
|
||
|
||
BowserInitializeIrpQueue(&NewTransport->WaitForNewMasterNameQueue);
|
||
|
||
BowserInitializeIrpQueue(&NewTransport->ChangeRoleQueue);
|
||
|
||
BowserInitializeTimer(&NewTransport->ElectionTimer);
|
||
|
||
BowserInitializeTimer(&NewTransport->FindMasterTimer);
|
||
|
||
PagedTransport->GlobalNext.Flink = NULL;
|
||
|
||
PagedTransport->GlobalNext.Blink = NULL;
|
||
|
||
InitializeListHead(&PagedTransport->NameChain);
|
||
|
||
PagedTransport->MasterName.Buffer = NULL;
|
||
|
||
PagedTransport->MasterBrowserAddress.Buffer = (PCHAR)(PagedTransport+1);
|
||
|
||
PagedTransport->MasterBrowserAddress.MaximumLength = max(sizeof(TA_IPX_ADDRESS),
|
||
sizeof(TA_NETBIOS_ADDRESS));
|
||
|
||
PagedTransport->TransportName.Buffer =
|
||
ALLOCATE_POOL(PagedPool,
|
||
TransportName->MaximumLength+sizeof(WCHAR), POOL_TRANSPORT_NAME);
|
||
|
||
if (PagedTransport->TransportName.Buffer == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ReturnStatus;
|
||
|
||
}
|
||
|
||
PagedTransport->TransportName.MaximumLength = TransportName->MaximumLength;
|
||
|
||
RtlCopyUnicodeString(&PagedTransport->TransportName, TransportName);
|
||
|
||
PagedTransport->TransportName.Buffer[(TransportName->Length/sizeof(WCHAR))] = UNICODE_NULL;
|
||
|
||
PagedTransport->MasterName.Buffer =
|
||
ALLOCATE_POOL(PagedPool,
|
||
(LM20_CNLEN+1)*sizeof(WCHAR), POOL_MASTERNAME);
|
||
|
||
if (PagedTransport->MasterName.Buffer == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
NewTransport->ComputerName = NULL;
|
||
|
||
NewTransport->PrimaryDomain = NULL;
|
||
|
||
NewTransport->MasterBrowser = NULL;
|
||
|
||
NewTransport->BrowserElection = NULL;
|
||
|
||
PagedTransport->MasterName.MaximumLength = (LM20_CNLEN+1)*sizeof(WCHAR);
|
||
|
||
PagedTransport->MasterName.Length = 0;
|
||
|
||
PagedTransport->BrowserServerListLength = 0;
|
||
|
||
PagedTransport->BrowserServerListBuffer = NULL;
|
||
|
||
PagedTransport->NumberOfBrowserServers = 0;
|
||
|
||
PagedTransport->Role = None;
|
||
|
||
PagedTransport->ServiceStatus = 0;
|
||
|
||
PagedTransport->IpxSocketHandle = NULL;
|
||
|
||
PagedTransport->IpSubnetNumber = BOWSER_NON_IP_SUBNET;
|
||
|
||
PagedTransport->DisabledTransport = TRUE;
|
||
PagedTransport->PointToPoint = FALSE;
|
||
|
||
//
|
||
// Initialize the time we last saw an election packet.
|
||
//
|
||
|
||
PagedTransport->LastElectionSeen = 0;
|
||
|
||
INITIALIZE_ANNOUNCE_DATABASE(NewTransport);
|
||
|
||
RtlInitializeGenericTable(&PagedTransport->AnnouncementTable,
|
||
BowserCompareAnnouncement,
|
||
BowserAllocateAnnouncement,
|
||
BowserFreeAnnouncement,
|
||
NULL);
|
||
|
||
RtlInitializeGenericTable(&PagedTransport->DomainTable,
|
||
BowserCompareAnnouncement,
|
||
BowserAllocateAnnouncement,
|
||
BowserFreeAnnouncement,
|
||
NULL);
|
||
|
||
InitializeListHead(&PagedTransport->BackupBrowserList);
|
||
|
||
PagedTransport->NumberOfBackupServerListEntries = 0;
|
||
|
||
//
|
||
// Get info from the provider
|
||
// (e.g., RAS, Wannish, DatagramSize)
|
||
|
||
Status= BowserUpdateProviderInformation( PagedTransport );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
PagedTransport->Flags = 0;
|
||
|
||
|
||
//
|
||
// We ignore any and all errors that occur when we open the IPX socket.
|
||
//
|
||
|
||
|
||
//
|
||
// Open the IPX mailslot socket.
|
||
//
|
||
|
||
Status = OpenIpxSocket(
|
||
&NewTransport->PagedTransport->IpxSocketHandle,
|
||
&NewTransport->IpxSocketFileObject,
|
||
&NewTransport->IpxSocketDeviceObject,
|
||
&NewTransport->PagedTransport->TransportName,
|
||
SMB_IPX_MAILSLOT_SOCKET
|
||
);
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
PagedTransport->Flags |= DIRECT_HOST_IPX;
|
||
// We'll use type 20 packets to increase the reach of broadcasts
|
||
// so don't treat this as a wannish protocol.
|
||
PagedTransport->Wannish = FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// Create the names for this transport.
|
||
//
|
||
|
||
InsertHeadList(&BowserTransportHead, &PagedTransport->GlobalNext);
|
||
|
||
for (NameEntry = BowserNameHead.Flink;
|
||
NameEntry != &BowserNameHead ;
|
||
NameEntry = NameEntry->Flink) {
|
||
PBOWSER_NAME Name = CONTAINING_RECORD(NameEntry, BOWSER_NAME, GlobalNext);
|
||
|
||
//
|
||
// If the name was added on all transports,
|
||
// add it on this transport, too.
|
||
//
|
||
|
||
if ( Name->AddedOnAllTransports ) {
|
||
|
||
if (!NT_SUCCESS(Status = BowserCreateTransportName(NewTransport, Name))) {
|
||
goto ReturnStatus;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Start receiving broadcasts on IPX now that the names exist.
|
||
//
|
||
|
||
if ( NewTransport->PagedTransport->Flags & DIRECT_HOST_IPX ) {
|
||
BowserEnableIpxDatagramSocket(NewTransport);
|
||
}
|
||
|
||
} else {
|
||
BowserDereferenceTransport( NewTransport );
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
ReturnStatus:
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Delete the transport.
|
||
//
|
||
|
||
if ( NewTransport != NULL ) {
|
||
BowserReferenceTransport( NewTransport );
|
||
BowserDeleteTransport (NewTransport);
|
||
BowserDereferenceTransport( NewTransport );
|
||
}
|
||
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserUnbindFromAllTransports(
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
Status = BowserForEachTransport(UnbindTransportWorker, NULL);
|
||
|
||
#if DBG
|
||
if (NT_SUCCESS(Status)) {
|
||
ASSERT (IsListEmpty(&BowserTransportHead));
|
||
}
|
||
#endif
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
UnbindTransportWorker(
|
||
IN PTRANSPORT Transport,
|
||
IN OUT PVOID Ctx
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the worker routine for BowserUnbindFromAllTransports.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Dereference the reference caused by the transport bind.
|
||
//
|
||
|
||
BowserDeleteTransport(Transport);
|
||
|
||
//
|
||
// Return success. We're done.
|
||
//
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
UNREFERENCED_PARAMETER(Ctx);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserFreeTransportByName (
|
||
IN PUNICODE_STRING TransportName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will deallocate an allocated transport
|
||
|
||
Arguments:
|
||
|
||
IN PUNICODE_STRING TransportName - Supplies a pointer to the name of the transport
|
||
to free
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PTRANSPORT Transport;
|
||
|
||
PAGED_CODE();
|
||
dprintf(DPRT_TDI, ("BowserFreeTransportByName: Remove transport %wZ\n", TransportName));
|
||
|
||
Transport = BowserFindTransport(TransportName);
|
||
|
||
if (Transport == NULL) {
|
||
|
||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||
}
|
||
|
||
//
|
||
// Remove the reference from the binding.
|
||
//
|
||
|
||
BowserDeleteTransport(Transport);
|
||
|
||
//
|
||
// Remove the reference from the FindTransport.
|
||
//
|
||
|
||
BowserDereferenceTransport(Transport);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
BowserEnumerateTransports (
|
||
OUT PVOID OutputBuffer,
|
||
OUT ULONG OutputBufferLength,
|
||
IN OUT PULONG EntriesRead,
|
||
IN OUT PULONG TotalEntries,
|
||
IN OUT PULONG TotalBytesNeeded,
|
||
IN ULONG OutputBufferDisplacement)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will enumerate the servers in the bowsers current announcement
|
||
table.
|
||
|
||
Arguments:
|
||
|
||
IN ULONG ServerTypeMask - Mask of servers to return.
|
||
IN PUNICODE_STRING DomainName OPTIONAL - Domain to filter (all if not specified)
|
||
OUT PVOID OutputBuffer - Buffer to fill with server info.
|
||
IN ULONG OutputBufferSize - Filled in with size of buffer.
|
||
OUT PULONG EntriesRead - Filled in with the # of entries returned.
|
||
OUT PULONG TotalEntries - Filled in with the total # of entries.
|
||
OUT PULONG TotalBytesNeeded - Filled in with the # of bytes needed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID OutputBufferEnd;
|
||
NTSTATUS Status;
|
||
ENUM_TRANSPORTS_CONTEXT Context;
|
||
PAGED_CODE();
|
||
|
||
OutputBufferEnd = (PCHAR)OutputBuffer+OutputBufferLength;
|
||
|
||
Context.EntriesRead = 0;
|
||
Context.TotalEntries = 0;
|
||
Context.TotalBytesNeeded = 0;
|
||
|
||
try {
|
||
Context.OutputBufferSize = OutputBufferLength;
|
||
Context.OutputBuffer = OutputBuffer;
|
||
Context.OutputBufferDisplacement = OutputBufferDisplacement;
|
||
Context.OutputBufferEnd = OutputBufferEnd;
|
||
Context.LastOutputBuffer = OutputBuffer;
|
||
|
||
dprintf(DPRT_FSCTL, ("Enumerate Transports: Buffer: %lx, BufferSize: %lx, BufferEnd: %lx\n",
|
||
OutputBuffer, OutputBufferLength, OutputBufferEnd));
|
||
|
||
Status = BowserForEachTransport(EnumerateTransportsWorker, &Context);
|
||
|
||
*EntriesRead = Context.EntriesRead;
|
||
*TotalEntries = Context.TotalEntries;
|
||
*TotalBytesNeeded = Context.TotalBytesNeeded;
|
||
|
||
if (*EntriesRead != 0) {
|
||
((PLMDR_TRANSPORT_LIST )Context.LastOutputBuffer)->NextEntryOffset = 0;
|
||
}
|
||
|
||
dprintf(DPRT_FSCTL, ("TotalEntries: %lx EntriesRead: %lx, TotalBytesNeeded: %lx\n", *TotalEntries, *EntriesRead, *TotalBytesNeeded));
|
||
|
||
if (*EntriesRead == *TotalEntries) {
|
||
try_return(Status = STATUS_SUCCESS);
|
||
} else {
|
||
try_return(Status = STATUS_MORE_ENTRIES);
|
||
}
|
||
try_exit:NOTHING;
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
EnumerateTransportsWorker(
|
||
IN PTRANSPORT Transport,
|
||
IN OUT PVOID Ctx
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the worker routine for BowserEnumerateTransports.
|
||
|
||
It is called for each of the serviced transports in the bowser and
|
||
returns the size needed to enumerate the servers received on each transport.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PENUM_TRANSPORTS_CONTEXT Context = Ctx;
|
||
PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
|
||
PAGED_CODE();
|
||
Context->TotalEntries += 1;
|
||
|
||
if ((ULONG)Context->OutputBufferEnd - (ULONG)Context->OutputBuffer >
|
||
sizeof(LMDR_TRANSPORT_LIST)+PagedTransport->TransportName.Length) {
|
||
PLMDR_TRANSPORT_LIST TransportEntry = (PLMDR_TRANSPORT_LIST)Context->OutputBuffer;
|
||
|
||
Context->LastOutputBuffer = Context->OutputBuffer;
|
||
|
||
Context->EntriesRead += 1;
|
||
|
||
RtlCopyMemory(TransportEntry->TransportName, PagedTransport->TransportName.Buffer, Transport->PagedTransport->TransportName.Length+sizeof(WCHAR));
|
||
|
||
//
|
||
// Null terminate the transport name.
|
||
//
|
||
|
||
TransportEntry->TransportName[PagedTransport->TransportName.Length/sizeof(WCHAR)] = '\0';
|
||
|
||
TransportEntry->TransportNameLength = PagedTransport->TransportName.Length;
|
||
|
||
TransportEntry->Flags = 0;
|
||
if (PagedTransport->Wannish) {
|
||
TransportEntry->Flags |= LMDR_TRANSPORT_WANNISH;
|
||
}
|
||
|
||
if (PagedTransport->PointToPoint) {
|
||
TransportEntry->Flags |= LMDR_TRANSPORT_RAS;
|
||
}
|
||
|
||
if (PagedTransport->Flags & DIRECT_HOST_IPX) {
|
||
TransportEntry->Flags |= LMDR_TRANSPORT_IPX;
|
||
}
|
||
|
||
TransportEntry->NextEntryOffset = PagedTransport->TransportName.Length+sizeof(LMDR_TRANSPORT_LIST)+sizeof(WCHAR);
|
||
|
||
TransportEntry->NextEntryOffset = ROUND_UP_COUNT(TransportEntry->NextEntryOffset, ALIGN_DWORD);
|
||
|
||
(PUCHAR)(Context->OutputBuffer) += TransportEntry->NextEntryOffset;
|
||
}
|
||
|
||
Context->TotalBytesNeeded += sizeof(LMDR_TRANSPORT_LIST)+PagedTransport->TransportName.Length;
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
VOID
|
||
BowserReferenceTransport(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
{
|
||
|
||
InterlockedIncrement(&Transport->ReferenceCount);
|
||
dprintf(DPRT_TDI, ("Reference transport %lx. Count now %lx\n", Transport, Transport->ReferenceCount));
|
||
|
||
}
|
||
|
||
VOID
|
||
BowserDereferenceTransport(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
{
|
||
LONG Result;
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
|
||
if (Transport->ReferenceCount == 0) {
|
||
InternalError(("Transport Reference Count mismatch\n"));
|
||
}
|
||
|
||
Result = InterlockedDecrement(&Transport->ReferenceCount);
|
||
|
||
|
||
dprintf(DPRT_TDI, ("Dereference transport %lx. Count now %lx\n", Transport, Transport->ReferenceCount));
|
||
|
||
if (Result == 0) {
|
||
//
|
||
// And free up the transport itself.
|
||
//
|
||
|
||
BowserpFreeTransport(Transport);
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserCreateTransportName (
|
||
IN PTRANSPORT Transport,
|
||
IN PBOWSER_NAME Name
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates a transport address object.
|
||
|
||
Arguments:
|
||
|
||
IN PTRANSPORT Transport - Supplies a transport structure describing the
|
||
transport address object to be created.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of resulting operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PTRANSPORT_NAME TransportName = NULL;
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = NULL;
|
||
PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
|
||
BOOLEAN ResourceAcquired = FALSE;
|
||
|
||
PAGED_CODE();
|
||
ASSERT(Transport->Signature == STRUCTURE_SIGNATURE_TRANSPORT);
|
||
|
||
dprintf(DPRT_TDI, ("BowserCreateTransportName. Transport %lx, Name %lx\n", Transport, Name));
|
||
|
||
//
|
||
// Link the transport_name structure into the transport list.
|
||
//
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
ResourceAcquired = TRUE;
|
||
|
||
TransportName = BowserFindTransportName(Transport, Name);
|
||
|
||
if (TransportName != NULL) {
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
#ifdef notdef
|
||
//
|
||
// Simply don't allocate certain names if the transport is disabled
|
||
//
|
||
|
||
if ( PagedTransport->DisabledTransport ) {
|
||
if ( Name->NameType == PrimaryDomainBrowser ) {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
#endif // notdef
|
||
|
||
ASSERT (IoGetCurrentProcess() == BowserFspProcess);
|
||
|
||
//
|
||
// Allocate a structure to refer to this name on the transport
|
||
//
|
||
|
||
TransportName = ALLOCATE_POOL(NonPagedPool, sizeof(TRANSPORT_NAME) +
|
||
max(sizeof(TA_NETBIOS_ADDRESS),
|
||
sizeof(TA_IPX_ADDRESS)), POOL_TRANSPORTNAME);
|
||
|
||
if (TransportName == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
goto error_cleanup;
|
||
}
|
||
|
||
TransportName->PagedTransportName = PagedTransportName =
|
||
ALLOCATE_POOL(PagedPool,
|
||
sizeof(PAGED_TRANSPORT_NAME),
|
||
POOL_PAGED_TRANSPORTNAME);
|
||
|
||
if (PagedTransportName == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
goto error_cleanup;
|
||
}
|
||
|
||
TransportName->Signature = STRUCTURE_SIGNATURE_TRANSPORTNAME;
|
||
|
||
TransportName->Size = sizeof(TRANSPORT_NAME);
|
||
|
||
TransportName->PagedTransportName = PagedTransportName;
|
||
|
||
// This TransportName is considered to be referenced by the transport via
|
||
// Transport->PagedTransport->NameChain. The Name->NameChain isn't
|
||
// considered to be a reference.
|
||
TransportName->ReferenceCount = 1;
|
||
|
||
PagedTransportName->NonPagedTransportName = TransportName;
|
||
|
||
PagedTransportName->Signature = STRUCTURE_SIGNATURE_PAGED_TRANSPORTNAME;
|
||
|
||
PagedTransportName->Size = sizeof(PAGED_TRANSPORT_NAME);
|
||
|
||
PagedTransportName->Name = Name;
|
||
|
||
BowserReferenceName(Name);
|
||
|
||
TransportName->Transport = Transport;
|
||
|
||
// Don't reference the Transport. When the transport is unbound, we'll
|
||
// make sure all the transport names are removed first.
|
||
// BowserReferenceTransport(Transport);
|
||
|
||
PagedTransportName->Handle = NULL;
|
||
|
||
TransportName->FileObject = NULL;
|
||
|
||
TransportName->DeviceObject = NULL;
|
||
|
||
InsertHeadList(&Transport->PagedTransport->NameChain, &PagedTransportName->TransportNext);
|
||
|
||
InsertHeadList(&Name->NameChain, &PagedTransportName->NameNext);
|
||
|
||
//
|
||
// If this is an OTHERDOMAIN, we want to process host announcements for
|
||
// the domain, if it isn't, we want to wait until we become a master.
|
||
//
|
||
|
||
if (Name->NameType == OtherDomain) {
|
||
|
||
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
|
||
DISCARDABLE_CODE( BowserDiscardableCodeSection );
|
||
|
||
TransportName->ProcessHostAnnouncements = TRUE;
|
||
} else {
|
||
TransportName->ProcessHostAnnouncements = FALSE;
|
||
}
|
||
|
||
//
|
||
// If this name is one of our special names, we want to remember it in
|
||
// the transport block.
|
||
//
|
||
|
||
if (Name->NameType == ComputerName) {
|
||
Transport->ComputerName = TransportName;
|
||
}
|
||
|
||
if (Name->NameType == PrimaryDomain) {
|
||
Transport->PrimaryDomain = TransportName;
|
||
}
|
||
|
||
if (Name->NameType == MasterBrowser) {
|
||
Transport->MasterBrowser = TransportName;
|
||
}
|
||
|
||
if (Name->NameType == BrowserElection) {
|
||
Transport->BrowserElection = TransportName;
|
||
}
|
||
|
||
TransportName->TransportAddress.Buffer = (PCHAR)(TransportName+1);
|
||
|
||
//
|
||
// Figure out what this name is, so we can match against it when
|
||
// a datagram is received.
|
||
//
|
||
|
||
Status = BowserBuildTransportAddress(&TransportName->TransportAddress, &Name->Name, Name->NameType, Transport);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto error_cleanup;
|
||
}
|
||
|
||
TransportName->NameType = Name->NameType;
|
||
|
||
#if DBG
|
||
if (Name->NameType == MasterBrowser) {
|
||
//
|
||
// make sure that we never become a master without locking the discardable code.
|
||
//
|
||
|
||
DISCARDABLE_CODE( BowserDiscardableCodeSection );
|
||
}
|
||
#endif
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
ResourceAcquired = FALSE;
|
||
|
||
//
|
||
// On non direct host IPX transports, we need to add the name now.
|
||
//
|
||
|
||
if (!FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
|
||
Status = BowserOpenNetbiosAddress(PagedTransportName, Transport, Name);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto error_cleanup;
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
|
||
error_cleanup:
|
||
dprintf(DPRT_TDI, ("BowserCreateTransportName failed. Name: %lx, Status %lx\n", TransportName, Status));
|
||
|
||
if (TransportName != NULL) {
|
||
BowserDereferenceTransportName(TransportName);
|
||
}
|
||
|
||
if (ResourceAcquired) {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserOpenNetbiosAddress(
|
||
IN PPAGED_TRANSPORT_NAME PagedTransportName,
|
||
IN PTRANSPORT Transport,
|
||
IN PBOWSER_NAME Name
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
PFILE_FULL_EA_INFORMATION EABuffer = NULL;
|
||
PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
|
||
OBJECT_ATTRIBUTES AddressAttributes;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
PAGED_CODE( );
|
||
|
||
try {
|
||
//
|
||
// Now create the address object for this name.
|
||
//
|
||
|
||
EABuffer = ALLOCATE_POOL(PagedPool, sizeof(FILE_FULL_EA_INFORMATION)-1 +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof(TA_NETBIOS_ADDRESS), POOL_EABUFFER);
|
||
|
||
|
||
if (EABuffer == NULL) {
|
||
try_return(Status = STATUS_INSUFFICIENT_RESOURCES)
|
||
|
||
}
|
||
|
||
EABuffer->NextEntryOffset = 0;
|
||
EABuffer->Flags = 0;
|
||
EABuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
||
EABuffer->EaValueLength = sizeof(TA_NETBIOS_ADDRESS);
|
||
|
||
ASSERT (TransportName->TransportAddress.Length == sizeof(TA_NETBIOS_ADDRESS));
|
||
|
||
RtlCopyMemory(EABuffer->EaName, TdiTransportAddress, EABuffer->EaNameLength+1);
|
||
|
||
RtlCopyMemory(&EABuffer->EaName[TDI_TRANSPORT_ADDRESS_LENGTH+1],
|
||
TransportName->TransportAddress.Buffer,
|
||
EABuffer->EaValueLength);
|
||
|
||
dprintf(DPRT_TDI, ("Create endpoint of \"%Z\" (%lx)", &Transport->PagedTransport->TransportName, TransportName));
|
||
|
||
InitializeObjectAttributes (&AddressAttributes,
|
||
&Transport->PagedTransport->TransportName, // Name
|
||
OBJ_CASE_INSENSITIVE,// Attributes
|
||
NULL, // RootDirectory
|
||
NULL); // SecurityDescriptor
|
||
|
||
Status = ZwCreateFile(&PagedTransportName->Handle, // Handle
|
||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
||
&AddressAttributes, // Object Attributes
|
||
&IoStatusBlock, // Final I/O status block
|
||
NULL, // Allocation Size
|
||
FILE_ATTRIBUTE_NORMAL, // Normal attributes
|
||
FILE_SHARE_READ,// Sharing attributes
|
||
FILE_OPEN_IF, // Create disposition
|
||
0, // CreateOptions
|
||
EABuffer, // EA Buffer
|
||
FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof(TA_NETBIOS_ADDRESS)); // EA length
|
||
|
||
FREE_POOL(EABuffer);
|
||
|
||
EABuffer = NULL;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
try_return(Status);
|
||
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status = IoStatusBlock.Status)) {
|
||
|
||
try_return(Status);
|
||
|
||
}
|
||
|
||
//
|
||
// Obtain a referenced pointer to the file object.
|
||
//
|
||
Status = ObReferenceObjectByHandle (
|
||
PagedTransportName->Handle,
|
||
0,
|
||
*IoFileObjectType,
|
||
KernelMode,
|
||
(PVOID *)&TransportName->FileObject,
|
||
NULL
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
try_return(Status);
|
||
|
||
}
|
||
|
||
//
|
||
// Get the address of the device object for the endpoint.
|
||
//
|
||
|
||
TransportName->DeviceObject = IoGetRelatedDeviceObject(TransportName->FileObject);
|
||
|
||
Status = BowserpTdiSetEventHandler(TransportName->DeviceObject,
|
||
TransportName->FileObject,
|
||
TDI_EVENT_RECEIVE_DATAGRAM,
|
||
(PVOID) BowserTdiReceiveDatagramHandler,
|
||
TransportName);
|
||
|
||
dprintf(DPRT_TDI, ("BowserCreateTransportName Succeeded. Name: %lx, Handle: %lx\n", TransportName, PagedTransportName->Handle));
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
if (EABuffer != NULL) {
|
||
FREE_POOL(EABuffer);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
BowserCloseNetbiosAddress( TransportName );
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
VOID
|
||
BowserCloseNetbiosAddress(
|
||
IN PTRANSPORT_NAME TransportName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Closes the Netbios Address for a transport name.
|
||
|
||
Arguments:
|
||
|
||
TransportName - Transport Name whose Netbios address is to be closed.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
// PTRANSPORT Transport = TransportName->Transport;
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = TransportName->PagedTransportName;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
if ( TransportName->FileObject != NULL ) {
|
||
ObDereferenceObject( TransportName->FileObject );
|
||
TransportName->FileObject = NULL;
|
||
}
|
||
|
||
if (PagedTransportName) {
|
||
|
||
if ( PagedTransportName->Handle != NULL ) {
|
||
BOOLEAN ProcessAttached = FALSE;
|
||
|
||
if (IoGetCurrentProcess() != BowserFspProcess) {
|
||
KeAttachProcess(BowserFspProcess);
|
||
|
||
ProcessAttached = TRUE;
|
||
}
|
||
|
||
Status = ZwClose( PagedTransportName->Handle );
|
||
|
||
if (ProcessAttached) {
|
||
KeDetachProcess();
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
dprintf(DPRT_TDI, ("BowserCloseNetbiosAddress: Free name %lx failed: %X, %lx Handle: %lx\n", TransportName, Status, PagedTransportName->Handle));
|
||
}
|
||
|
||
PagedTransportName->Handle = NULL;
|
||
}
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
BowserCloseAllNetbiosAddresses(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine closes all the Netbios address this transport has open
|
||
to the TDI driver.
|
||
|
||
Arguments:
|
||
|
||
Transport - The transport whose Netbios addresses are to be closed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of resulting operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY NameEntry;
|
||
PLIST_ENTRY NextEntry;
|
||
|
||
PAGED_CODE();
|
||
dprintf(DPRT_TDI, ("BowserCloseAllNetbiosAddresses: Close addresses for transport %lx\n", Transport));
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
for (NameEntry = Transport->PagedTransport->NameChain.Flink;
|
||
NameEntry != &Transport->PagedTransport->NameChain;
|
||
NameEntry = NextEntry) {
|
||
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
|
||
PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
|
||
|
||
NextEntry = NameEntry->Flink;
|
||
|
||
BowserCloseNetbiosAddress(TransportName);
|
||
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
return;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserEnableIpxDatagramSocket(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
NWLINK_ACTION action;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Put the endpoint in broadcast reception mode.
|
||
//
|
||
|
||
action.Header.TransportId = 'XPIM'; // "MIPX"
|
||
action.Header.ActionCode = 0;
|
||
action.Header.Reserved = 0;
|
||
action.OptionType = TRUE;
|
||
action.BufferLength = sizeof(action.Option);
|
||
action.Option = MIPX_RCVBCAST;
|
||
|
||
status = BowserIssueTdiAction(
|
||
Transport->IpxSocketDeviceObject,
|
||
Transport->IpxSocketFileObject,
|
||
(PCHAR)&action,
|
||
sizeof(action)
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Set the default packet type to 20 to force all browser packets
|
||
// through routers.
|
||
//
|
||
|
||
action.Header.TransportId = 'XPIM'; // "MIPX"
|
||
action.Header.ActionCode = 0;
|
||
action.Header.Reserved = 0;
|
||
action.OptionType = TRUE;
|
||
action.BufferLength = sizeof(action.Option);
|
||
action.Option = MIPX_SETSENDPTYPE;
|
||
action.Data[0] = IPX_BROADCAST_PACKET;
|
||
|
||
status = BowserIssueTdiAction(
|
||
Transport->IpxSocketDeviceObject,
|
||
Transport->IpxSocketFileObject,
|
||
(PCHAR)&action,
|
||
sizeof(action)
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Register the browser Receive Datagram event handler.
|
||
//
|
||
|
||
status = BowserpTdiSetEventHandler(
|
||
Transport->IpxSocketDeviceObject,
|
||
Transport->IpxSocketFileObject,
|
||
TDI_EVENT_RECEIVE_DATAGRAM,
|
||
BowserIpxDatagramHandler,
|
||
Transport
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
// INTERNAL_ERROR(
|
||
// ERROR_LEVEL_EXPECTED,
|
||
// "OpenNonNetbiosAddress: set receive datagram event handler failed: %X",
|
||
// status,
|
||
// NULL
|
||
// );
|
||
// SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
|
||
goto cleanup;
|
||
}
|
||
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
//
|
||
// Out-of-line error cleanup.
|
||
//
|
||
|
||
cleanup:
|
||
|
||
//
|
||
// Something failed. Clean up as appropriate.
|
||
//
|
||
|
||
if ( Transport->IpxSocketFileObject != NULL ) {
|
||
ObDereferenceObject( Transport->IpxSocketFileObject );
|
||
Transport->IpxSocketFileObject = NULL;
|
||
}
|
||
if ( Transport->PagedTransport->IpxSocketHandle != NULL ) {
|
||
ZwClose( Transport->PagedTransport->IpxSocketHandle );
|
||
Transport->PagedTransport->IpxSocketHandle = NULL;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
OpenIpxSocket (
|
||
OUT PHANDLE Handle,
|
||
OUT PFILE_OBJECT *FileObject,
|
||
OUT PDEVICE_OBJECT *DeviceObject,
|
||
IN PUNICODE_STRING DeviceName,
|
||
IN USHORT Socket
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG length;
|
||
PFILE_FULL_EA_INFORMATION ea;
|
||
TA_IPX_ADDRESS ipxAddress;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
IO_STATUS_BLOCK iosb;
|
||
|
||
CHAR buffer[sizeof(FILE_FULL_EA_INFORMATION) +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof(TA_IPX_ADDRESS)];
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Build the IPX socket address.
|
||
//
|
||
|
||
length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof(TA_IPX_ADDRESS);
|
||
ea = (PFILE_FULL_EA_INFORMATION)buffer;
|
||
|
||
ea->NextEntryOffset = 0;
|
||
ea->Flags = 0;
|
||
ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
||
ea->EaValueLength = sizeof (TA_IPX_ADDRESS);
|
||
|
||
RtlCopyMemory( ea->EaName, TdiTransportAddress, ea->EaNameLength + 1 );
|
||
|
||
//
|
||
// Create a copy of the NETBIOS address descriptor in a local
|
||
// first, in order to avoid alignment problems.
|
||
//
|
||
|
||
ipxAddress.TAAddressCount = 1;
|
||
ipxAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
|
||
ipxAddress.Address[0].AddressLength = sizeof (TDI_ADDRESS_IPX);
|
||
ipxAddress.Address[0].Address[0].NetworkAddress = 0;
|
||
RtlZeroMemory(ipxAddress.Address[0].Address[0].NodeAddress, sizeof(ipxAddress.Address[0].Address[0].NodeAddress));
|
||
ipxAddress.Address[0].Address[0].Socket = Socket;
|
||
|
||
RtlCopyMemory(
|
||
&ea->EaName[ea->EaNameLength + 1],
|
||
&ipxAddress,
|
||
sizeof(TA_IPX_ADDRESS)
|
||
);
|
||
|
||
InitializeObjectAttributes( &objectAttributes, DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL );
|
||
|
||
status = NtCreateFile (
|
||
Handle,
|
||
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access
|
||
&objectAttributes, // object attributes
|
||
&iosb, // returned status information
|
||
NULL, // block size (unused)
|
||
0, // file attributes
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
|
||
FILE_CREATE, // create disposition
|
||
0, // create options
|
||
buffer, // EA buffer
|
||
length // EA length
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
// KdPrint(( "Status of opening ipx socket %x on %wZ is %x\n",
|
||
// Socket, DeviceName, status ));
|
||
return status;
|
||
}
|
||
|
||
// KdPrint(( "IPX socket %x opened!\n", Socket ));
|
||
|
||
status = ObReferenceObjectByHandle (
|
||
*Handle,
|
||
0,
|
||
*IoFileObjectType,
|
||
KernelMode,
|
||
(PVOID *)FileObject,
|
||
NULL
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
ZwClose(*Handle);
|
||
*Handle = NULL;
|
||
}
|
||
|
||
*DeviceObject = IoGetRelatedDeviceObject(*FileObject);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // OpenIpxSocket
|
||
|
||
|
||
VOID
|
||
BowserReferenceTransportName(
|
||
IN PTRANSPORT_NAME TransportName
|
||
)
|
||
{
|
||
InterlockedIncrement(&TransportName->ReferenceCount);
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserDereferenceTransportName(
|
||
IN PTRANSPORT_NAME TransportName
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
LONG Result;
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
|
||
if (TransportName->ReferenceCount == 0) {
|
||
InternalError(("Transport Name Reference Count mismatch\n"));
|
||
}
|
||
|
||
Result = InterlockedDecrement(&TransportName->ReferenceCount);
|
||
|
||
if (Result == 0) {
|
||
Status = BowserFreeTransportName(TransportName);
|
||
} else {
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserpTdiRemoveAddresses(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine removes all the transport names associated with a transport
|
||
|
||
Arguments:
|
||
|
||
IN PTRANSPORT Transport - Supplies a transport structure describing the
|
||
transport address object to be created.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of resulting operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY NameEntry;
|
||
PLIST_ENTRY NextEntry;
|
||
|
||
PAGED_CODE();
|
||
dprintf(DPRT_TDI, ("BowserpTdiRemoveAddresses: Remove addresses for transport %lx\n", Transport));
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
for (NameEntry = Transport->PagedTransport->NameChain.Flink;
|
||
NameEntry != &Transport->PagedTransport->NameChain;
|
||
NameEntry = NextEntry) {
|
||
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
|
||
PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
|
||
|
||
//
|
||
// Remove the TransportName from the list of transport names for
|
||
// this transport.
|
||
//
|
||
NextEntry = NameEntry->Flink;
|
||
RemoveEntryList(&PagedTransportName->TransportNext);
|
||
PagedTransportName->TransportNext.Flink = NULL;
|
||
PagedTransportName->TransportNext.Blink = NULL;
|
||
|
||
|
||
//
|
||
// Since we delinked it, we need to dereference it.
|
||
//
|
||
Status = BowserDereferenceTransportName(TransportName);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
return(Status);
|
||
}
|
||
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
PTRANSPORT_NAME
|
||
BowserFindTransportName(
|
||
IN PTRANSPORT Transport,
|
||
IN PBOWSER_NAME Name
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks up a given browser name to find its associated
|
||
transport address.
|
||
|
||
Arguments:
|
||
|
||
IN PTRANSPORT Transport - Supplies a transport structure describing the
|
||
transport address object to be created.
|
||
|
||
IN PBOWSER_NAME Name - Supplies the name to look up.
|
||
|
||
Return Value:
|
||
|
||
The transport address found, or null.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY NameEntry;
|
||
PTRANSPORT_NAME RetValue = NULL;
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
try {
|
||
for (NameEntry = Transport->PagedTransport->NameChain.Flink;
|
||
NameEntry != &Transport->PagedTransport->NameChain;
|
||
NameEntry = NameEntry->Flink) {
|
||
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = CONTAINING_RECORD(NameEntry, PAGED_TRANSPORT_NAME, TransportNext);
|
||
PTRANSPORT_NAME TransportName = PagedTransportName->NonPagedTransportName;
|
||
|
||
if (PagedTransportName->Name == Name) {
|
||
|
||
try_return(RetValue = TransportName);
|
||
}
|
||
|
||
try_exit:NOTHING;
|
||
}
|
||
} finally {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
return RetValue;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserFreeTransportName(
|
||
IN PTRANSPORT_NAME TransportName
|
||
)
|
||
{
|
||
PTRANSPORT Transport = TransportName->Transport;
|
||
PBOWSER_NAME Name = NULL;
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = TransportName->PagedTransportName;
|
||
|
||
PAGED_CODE();
|
||
dprintf(DPRT_TDI, ("BowserFreeTransportName: Free name %lx\n", TransportName));
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
//
|
||
// Close the handle to the TDI driver.
|
||
//
|
||
BowserCloseNetbiosAddress( TransportName );
|
||
|
||
//
|
||
// If we received a message which re-referenced this transport name,
|
||
// just return now. We'll be back when the reference count gets
|
||
// re-dereferenced to zero.
|
||
//
|
||
|
||
if ( TransportName->ReferenceCount != 0 ) {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
ASSERT (TransportName->ReferenceCount == 0);
|
||
|
||
|
||
|
||
if (PagedTransportName) {
|
||
|
||
|
||
//
|
||
// If this transport name has not yet been delinked,
|
||
// delink it.
|
||
//
|
||
|
||
if ( PagedTransportName->TransportNext.Flink != NULL ) {
|
||
// This should only happen on a failed transport name creation.
|
||
RemoveEntryList(&PagedTransportName->TransportNext);
|
||
PagedTransportName->TransportNext.Flink = NULL;
|
||
PagedTransportName->TransportNext.Blink = NULL;
|
||
}
|
||
RemoveEntryList(&PagedTransportName->NameNext);
|
||
|
||
|
||
//
|
||
// We're removing an OtherDomain - we can remove the reference to
|
||
// the discardable code section that was applied when the name was
|
||
// created.
|
||
//
|
||
|
||
if (PagedTransportName->Name->NameType == OtherDomain) {
|
||
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
}
|
||
|
||
Name = PagedTransportName->Name;
|
||
|
||
FREE_POOL(PagedTransportName);
|
||
}
|
||
|
||
if (Name != NULL) {
|
||
if (Name->NameType == ComputerName) {
|
||
Transport->ComputerName = NULL;
|
||
}
|
||
|
||
if (Name->NameType == PrimaryDomain) {
|
||
Transport->PrimaryDomain = NULL;
|
||
}
|
||
|
||
if (Name->NameType == MasterBrowser) {
|
||
Transport->MasterBrowser = NULL;
|
||
}
|
||
|
||
if (Name->NameType == BrowserElection) {
|
||
Transport->BrowserElection = NULL;
|
||
}
|
||
|
||
BowserDereferenceName(Name);
|
||
|
||
}
|
||
|
||
FREE_POOL(TransportName);
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
dprintf(DPRT_TDI, ("BowserFreeTransportName: Free name %lx completed\n", TransportName));
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
VOID
|
||
BowserDeleteTransport(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Delete a transport.
|
||
|
||
The caller should have a single reference to the transport. The actual
|
||
transport structure will be deleted when that reference goes away.
|
||
This routine will decrement the global reference made in
|
||
BowserTdiAllocateTransport
|
||
|
||
Arguments:
|
||
|
||
IN Transport - Supplies a transport structure to be deleted.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LARGE_INTEGER Interval;
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
//
|
||
// Prevent BowserFindTransport from adding any new references to the transport
|
||
//
|
||
|
||
if ( Transport->PagedTransport != NULL &&
|
||
Transport->PagedTransport->GlobalNext.Flink != NULL ) {
|
||
RemoveEntryList(&Transport->PagedTransport->GlobalNext);
|
||
}
|
||
|
||
//
|
||
// Close all handles to the TDI driver so we won't get any indications after
|
||
// we start cleaning up the Transport structure in BowserpFreeTransport.
|
||
//
|
||
|
||
BowserCloseAllNetbiosAddresses( Transport );
|
||
|
||
if ( Transport->PagedTransport != NULL &&
|
||
Transport->PagedTransport->IpxSocketHandle != NULL) {
|
||
|
||
NTSTATUS LocalStatus;
|
||
BOOLEAN ProcessAttached = FALSE;
|
||
|
||
if (IoGetCurrentProcess() != BowserFspProcess) {
|
||
KeAttachProcess(BowserFspProcess);
|
||
|
||
ProcessAttached = TRUE;
|
||
}
|
||
|
||
LocalStatus = ZwClose(Transport->PagedTransport->IpxSocketHandle);
|
||
ASSERT(NT_SUCCESS(LocalStatus));
|
||
|
||
if (ProcessAttached) {
|
||
KeDetachProcess();
|
||
}
|
||
|
||
Transport->PagedTransport->IpxSocketHandle = NULL;
|
||
}
|
||
|
||
//
|
||
// Uninitialize the timers to ensure we aren't in a timer routine while
|
||
// we are cleaning up.
|
||
//
|
||
|
||
BowserUninitializeTimer(&Transport->ElectionTimer);
|
||
|
||
BowserUninitializeTimer(&Transport->FindMasterTimer);
|
||
|
||
//
|
||
// Remove the global reference to the transport.
|
||
//
|
||
|
||
BowserDereferenceTransport( Transport );
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
//
|
||
// Delete any mailslot messages queued to the netlogon service.
|
||
//
|
||
|
||
BowserNetlogonDeleteTransportFromMessageQueue ( Transport );
|
||
|
||
|
||
//
|
||
// Loop until our caller has the last outstanding reference.
|
||
// This is the only thing preventing the driver from unloading while there
|
||
// are still references outstanding.
|
||
//
|
||
|
||
while ( Transport->ReferenceCount != 1) {
|
||
Interval.QuadPart = -1*10*1000*10; // .01 second
|
||
KeDelayExecutionThread( KernelMode, FALSE, &Interval );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
BowserpFreeTransport(
|
||
IN PTRANSPORT Transport
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
//
|
||
// Free the Paged transport, if necessary.
|
||
//
|
||
|
||
if (Transport->PagedTransport != NULL) {
|
||
PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
|
||
|
||
//
|
||
// Remove the Adresses.
|
||
//
|
||
// Do this in a separate step from the Close in BowserDeleteTransport
|
||
// above to ensure the PrimaryDomain and ComputerName fields don't
|
||
// get cleared until all possible references are removed.
|
||
//
|
||
|
||
if (!IsListEmpty( &PagedTransport->NameChain)) {
|
||
BowserpTdiRemoveAddresses(Transport);
|
||
}
|
||
|
||
BowserDeleteGenericTable(&PagedTransport->AnnouncementTable);
|
||
|
||
BowserDeleteGenericTable(&PagedTransport->DomainTable);
|
||
|
||
if (PagedTransport->MasterName.Buffer != NULL) {
|
||
FREE_POOL(PagedTransport->MasterName.Buffer);
|
||
}
|
||
|
||
if (PagedTransport->TransportName.Buffer != NULL) {
|
||
FREE_POOL(PagedTransport->TransportName.Buffer);
|
||
}
|
||
|
||
FREE_POOL(PagedTransport);
|
||
}
|
||
|
||
|
||
ExDeleteResource(&Transport->BrowserServerListResource);
|
||
|
||
UNINITIALIZE_ANNOUNCE_DATABASE(Transport);
|
||
|
||
ExDeleteResource(&Transport->Lock);
|
||
|
||
BowserUninitializeIrpQueue(&Transport->BecomeBackupQueue);
|
||
|
||
BowserUninitializeIrpQueue(&Transport->BecomeMasterQueue);
|
||
|
||
BowserUninitializeIrpQueue(&Transport->FindMasterQueue);
|
||
|
||
BowserUninitializeIrpQueue(&Transport->WaitForMasterAnnounceQueue);
|
||
|
||
if ( Transport->IpxSocketFileObject != NULL ) {
|
||
ObDereferenceObject( Transport->IpxSocketFileObject );
|
||
}
|
||
|
||
FREE_POOL(Transport);
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserpTdiSetEventHandler (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PFILE_OBJECT FileObject,
|
||
IN ULONG EventType,
|
||
IN PVOID EventHandler,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine registers an event handler with a TDI transport provider.
|
||
|
||
Arguments:
|
||
|
||
IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
|
||
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
|
||
IN ULONG EventType, - Supplies the type of event.
|
||
IN PVOID EventHandler - Supplies the event handler.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the set event operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIRP Irp;
|
||
|
||
PAGED_CODE();
|
||
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
||
|
||
if (Irp == NULL) {
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
|
||
NULL, NULL,
|
||
EventType, EventHandler, Context);
|
||
|
||
Status = BowserSubmitTdiRequest(FileObject, Irp);
|
||
|
||
IoFreeIrp(Irp);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserIssueTdiAction (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PVOID Action,
|
||
IN ULONG ActionSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine registers an event handler with a TDI transport provider.
|
||
|
||
Arguments:
|
||
|
||
IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
|
||
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
|
||
IN ULONG EventType, - Supplies the type of event.
|
||
IN PVOID EventHandler - Supplies the event handler.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of the set event operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIRP irp;
|
||
// PIO_STACK_LOCATION irpSp;
|
||
PMDL mdl;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
||
|
||
if (irp == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Allocate and build an MDL that we'll use to describe the output
|
||
// buffer for the request.
|
||
//
|
||
|
||
mdl = IoAllocateMdl( Action, ActionSize, FALSE, FALSE, NULL );
|
||
|
||
if ( mdl == NULL ) {
|
||
IoFreeIrp( irp );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
MmBuildMdlForNonPagedPool( mdl );
|
||
|
||
TdiBuildAction(
|
||
irp,
|
||
DeviceObject,
|
||
FileObject,
|
||
NULL,
|
||
NULL,
|
||
mdl
|
||
);
|
||
|
||
irp->AssociatedIrp.SystemBuffer = Action;
|
||
|
||
if (irp == NULL) {
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
status = BowserSubmitTdiRequest(FileObject, irp);
|
||
|
||
IoFreeIrp(irp);
|
||
|
||
IoFreeMdl(mdl);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
BowserBuildTransportAddress (
|
||
IN OUT PANSI_STRING Address,
|
||
IN PUNICODE_STRING Name,
|
||
IN DGRECEIVER_NAME_TYPE NameType,
|
||
IN PTRANSPORT Transport
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a computer name (PUNICODE_STRING) and converts it into an
|
||
acceptable form for passing in as transport address.
|
||
|
||
Arguments:
|
||
|
||
OUT PTA_NETBIOS_ADDRESS RemoteAddress, - Supplies the structure to fill in
|
||
IN PUNICODE_STRING Name - Supplies the name to put into the transport
|
||
|
||
Please note that it is CRITICAL that the TA_NETBIOS_ADDRESS pointed to by
|
||
RemoteAddress be of sufficient size to hold the full network name.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
OEM_STRING NetBiosName;
|
||
PTRANSPORT_ADDRESS RemoteAddress = (PTRANSPORT_ADDRESS)Address->Buffer;
|
||
PTDI_ADDRESS_NETBIOS NetbiosAddress = (PTDI_ADDRESS_NETBIOS)&RemoteAddress->Address[0].Address[0];
|
||
|
||
PAGED_CODE();
|
||
|
||
RemoteAddress->TAAddressCount = 1;
|
||
RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
|
||
Address->Length = sizeof(TA_NETBIOS_ADDRESS);
|
||
|
||
if (RtlUnicodeStringToOemSize(Name) > NETBIOS_NAME_LEN) {
|
||
return STATUS_BAD_NETWORK_PATH;
|
||
}
|
||
|
||
NetBiosName.Length = 0;
|
||
NetBiosName.MaximumLength = NETBIOS_NAME_LEN;
|
||
NetBiosName.Buffer = NetbiosAddress->NetbiosName;
|
||
|
||
if (NameType != DomainAnnouncement) {
|
||
|
||
Status = RtlUpcaseUnicodeStringToOemString(&NetBiosName, Name, FALSE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
RtlCopyMemory(&NetBiosName.Buffer[NetBiosName.Length], " ",
|
||
NETBIOS_NAME_LEN-NetBiosName.Length);
|
||
} else {
|
||
//
|
||
// Domain announcement names are simply filled with nulls. All other
|
||
// names are padded with spaces.
|
||
//
|
||
|
||
ASSERT (strlen(DOMAIN_ANNOUNCEMENT_NAME) == NETBIOS_NAME_LEN);
|
||
RtlCopyMemory(NetBiosName.Buffer, DOMAIN_ANNOUNCEMENT_NAME, strlen(DOMAIN_ANNOUNCEMENT_NAME));
|
||
}
|
||
|
||
switch (NameType) {
|
||
|
||
case DomainAnnouncement:
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
|
||
break;
|
||
|
||
case ComputerName:
|
||
case AlternateComputerName:
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = WORKSTATION_SIGNATURE;
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
break;
|
||
|
||
case DomainName:
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = DOMAIN_CONTROLLER_SIGNATURE;
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
|
||
break;
|
||
|
||
case BrowserServer:
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = SERVER_SIGNATURE;
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
break;
|
||
|
||
case MasterBrowser:
|
||
if (Transport->PagedTransport->Flags & DIRECT_HOST_IPX) {
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = WORKSTATION_SIGNATURE;
|
||
} else {
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = MASTER_BROWSER_SIGNATURE;
|
||
}
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
break;
|
||
|
||
case PrimaryDomain:
|
||
case OtherDomain:
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = PRIMARY_DOMAIN_SIGNATURE;
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
|
||
break;
|
||
|
||
case PrimaryDomainBrowser:
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = PRIMARY_CONTROLLER_SIGNATURE;
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
break;
|
||
|
||
case BrowserElection:
|
||
if (Transport->PagedTransport->Flags & DIRECT_HOST_IPX) {
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = WORKSTATION_SIGNATURE;
|
||
} else {
|
||
NetbiosAddress->NetbiosName[NETBIOS_NAME_LEN-1] = BROWSER_ELECTION_SIGNATURE;
|
||
}
|
||
NetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
|
||
break;
|
||
default:
|
||
return STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserUpdateProviderInformation(
|
||
IN OUT PPAGED_TRANSPORT PagedTransport
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine updates status bits in the PagedTransport based on querying
|
||
the TDI driver.
|
||
|
||
Most importantly, the transport will be disabled if the provider is RAS or
|
||
doesn't yet have an IP address.
|
||
|
||
Arguments:
|
||
|
||
PagedTransport - Transport to update
|
||
|
||
Return Value:
|
||
|
||
Status of operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
TDI_PROVIDER_INFO ProviderInfo;
|
||
ULONG OldIpSubnetNumber;
|
||
BOOLEAN DisableThisTransport = FALSE;
|
||
|
||
PLIST_ENTRY TransportEntry;
|
||
PPAGED_TRANSPORT CurrentPagedTransport;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
//
|
||
// Find out about the transport.
|
||
//
|
||
|
||
OldIpSubnetNumber = PagedTransport->IpSubnetNumber;
|
||
|
||
Status = BowserDetermineProviderInformation(
|
||
&PagedTransport->TransportName,
|
||
&ProviderInfo,
|
||
&PagedTransport->IpSubnetNumber );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
//
|
||
// We can only talk to transports that support a max datagram size.
|
||
//
|
||
|
||
if (ProviderInfo.MaxDatagramSize == 0) {
|
||
Status = STATUS_BAD_REMOTE_ADAPTER;
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
PagedTransport->NonPagedTransport->DatagramSize = ProviderInfo.MaxDatagramSize;
|
||
|
||
|
||
//
|
||
// Remember various attributes of the provider
|
||
// (Never disable the PointToPoint bit. NetBt forgets it when the
|
||
// RAS phone is hung up.)
|
||
|
||
PagedTransport->Wannish = (BOOLEAN)((ProviderInfo.ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) != 0);
|
||
if (ProviderInfo.ServiceFlags & TDI_SERVICE_POINT_TO_POINT) {
|
||
PagedTransport->PointToPoint = TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// If this is a RAS transport or the IP Address is not yet known,
|
||
// disable browsing on the transport.
|
||
//
|
||
|
||
if ( PagedTransport->PointToPoint ||
|
||
PagedTransport->IpSubnetNumber == 0 ) {
|
||
DisableThisTransport = TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// If this isn't an IP transport, we're done.
|
||
//
|
||
|
||
if ( PagedTransport->IpSubnetNumber == BOWSER_NON_IP_SUBNET ) {
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
//
|
||
// In the loop below, we use OldIpSubnetNumber to determine if another
|
||
// transport should be enabled on that subnet. If that will NEVER be
|
||
// appropriate, flag OldIpSubnetNumber now.
|
||
//
|
||
|
||
if ( OldIpSubnetNumber == 0 ||
|
||
PagedTransport->DisabledTransport ||
|
||
PagedTransport->IpSubnetNumber == OldIpSubnetNumber ) {
|
||
OldIpSubnetNumber = BOWSER_NON_IP_SUBNET;
|
||
}
|
||
|
||
|
||
//
|
||
// Loop through the transports enabling/disabling them as indicated by
|
||
// the comments below.
|
||
//
|
||
|
||
for (TransportEntry = BowserTransportHead.Flink ;
|
||
TransportEntry != &BowserTransportHead ;
|
||
TransportEntry = CurrentPagedTransport->GlobalNext.Flink ) {
|
||
|
||
CurrentPagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
|
||
|
||
//
|
||
// If this transport isn't an IP transport,
|
||
// or this transport is a RAS transport,
|
||
// or this transport is the transport passed in,
|
||
// skip it and go on to the next one.
|
||
//
|
||
if ( CurrentPagedTransport->IpSubnetNumber == BOWSER_NON_IP_SUBNET ||
|
||
CurrentPagedTransport->PointToPoint ||
|
||
CurrentPagedTransport == PagedTransport ) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Special case this transport if it's currently disabled
|
||
//
|
||
|
||
if ( CurrentPagedTransport->DisabledTransport ) {
|
||
|
||
//
|
||
// If this transport is disabled and the transport passed in
|
||
// used to be the enabled transport for the subnet,
|
||
// enable the transport
|
||
//
|
||
|
||
if ( CurrentPagedTransport->IpSubnetNumber == OldIpSubnetNumber ) {
|
||
CurrentPagedTransport->DisabledTransport = FALSE;
|
||
}
|
||
|
||
//
|
||
// In any case,
|
||
// that's all we need to do for a disabled transport.
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
|
||
//
|
||
// If this transport is an enabled transport for the subnet of the one
|
||
// passed in,
|
||
// then disable the one passed in.
|
||
//
|
||
|
||
if ( CurrentPagedTransport->IpSubnetNumber ==
|
||
PagedTransport->IpSubnetNumber ) {
|
||
DisableThisTransport = TRUE;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Cleanup
|
||
//
|
||
ReturnStatus:
|
||
|
||
//
|
||
// If we're disabling a previously enabled transport,
|
||
// ensure we're not the master browser.
|
||
//
|
||
if ( DisableThisTransport && !PagedTransport->DisabledTransport ) {
|
||
PagedTransport->DisabledTransport = DisableThisTransport;
|
||
BowserLoseElection( PagedTransport->NonPagedTransport );
|
||
} else {
|
||
PagedTransport->DisabledTransport = DisableThisTransport;
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserDetermineProviderInformation(
|
||
IN PUNICODE_STRING TransportName,
|
||
OUT PTDI_PROVIDER_INFO ProviderInfo,
|
||
OUT PULONG IpSubnetNumber
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will determine provider information about a transport.
|
||
|
||
Arguments:
|
||
|
||
TransportName - Supplies the name of the transport provider
|
||
|
||
ProviderInfo - Returns information about the provider
|
||
|
||
IpSubnetNumber - returns the Ip Subnet Number of this transport.
|
||
BOWSER_NON_IP_SUBNET - If this isn't an IP transport
|
||
0 - If the IP address isn't yet set
|
||
Otherwise - the IP address anded with the subnet mask
|
||
|
||
Return Value:
|
||
|
||
Status of operation.
|
||
|
||
--*/
|
||
{
|
||
HANDLE TransportHandle = NULL;
|
||
PFILE_OBJECT TransportObject = NULL;
|
||
OBJECT_ATTRIBUTES ObjAttributes;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PIRP Irp;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
PMDL Mdl = NULL;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
InitializeObjectAttributes (&ObjAttributes,
|
||
TransportName, // Name
|
||
OBJ_CASE_INSENSITIVE, // Attributes
|
||
NULL, // RootDirectory
|
||
NULL); // SecurityDescriptor
|
||
|
||
|
||
Status = ZwCreateFile(&TransportHandle, // Handle
|
||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
||
&ObjAttributes, // Object Attributes
|
||
&IoStatusBlock, // Final I/O status block
|
||
NULL, // Allocation Size
|
||
FILE_ATTRIBUTE_NORMAL, // Normal attributes
|
||
FILE_SHARE_READ, // Sharing attributes
|
||
FILE_OPEN_IF, // Create disposition
|
||
0, // CreateOptions
|
||
NULL, // EA Buffer
|
||
0); // EA Buffer Length
|
||
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
Status = ObReferenceObjectByHandle (
|
||
TransportHandle,
|
||
0,
|
||
*IoFileObjectType,
|
||
KernelMode,
|
||
(PVOID *)&TransportObject,
|
||
NULL
|
||
);
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
DeviceObject = IoGetRelatedDeviceObject(TransportObject);
|
||
|
||
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
||
|
||
if (Irp == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
//
|
||
// Allocate an MDL to hold the provider info.
|
||
//
|
||
|
||
Mdl = IoAllocateMdl(ProviderInfo, sizeof(TDI_PROVIDER_INFO),
|
||
FALSE,
|
||
FALSE,
|
||
NULL);
|
||
|
||
MmBuildMdlForNonPagedPool(Mdl);
|
||
|
||
TdiBuildQueryInformation(Irp, DeviceObject, TransportObject,
|
||
NULL, NULL,
|
||
TDI_QUERY_PROVIDER_INFORMATION, Mdl);
|
||
|
||
Status = BowserSubmitTdiRequest(TransportObject, Irp);
|
||
|
||
IoFreeIrp(Irp);
|
||
|
||
//
|
||
// Get the IP address for this Transport.
|
||
//
|
||
|
||
if ( (ProviderInfo->ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED) == 0) {
|
||
*IpSubnetNumber = BOWSER_NON_IP_SUBNET;
|
||
} else {
|
||
NTSTATUS TempStatus;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
ULONG IpAddressBuffer[2]; // IpAddress followed by subnet mask
|
||
|
||
TempStatus = ZwDeviceIoControlFile(
|
||
TransportHandle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
IOCTL_NETBT_GET_IP_SUBNET,
|
||
NULL,
|
||
0,
|
||
&IpAddressBuffer,
|
||
sizeof(IpAddressBuffer) );
|
||
|
||
if ( !NT_SUCCESS(TempStatus) ) {
|
||
*IpSubnetNumber = BOWSER_NON_IP_SUBNET;
|
||
} else {
|
||
ASSERT(TempStatus != STATUS_PENDING);
|
||
*IpSubnetNumber = IpAddressBuffer[0] & IpAddressBuffer[1];
|
||
}
|
||
}
|
||
|
||
|
||
ReturnStatus:
|
||
if (Mdl != NULL) {
|
||
IoFreeMdl(Mdl);
|
||
}
|
||
|
||
if (TransportObject != NULL) {
|
||
ObDereferenceObject(TransportObject);
|
||
}
|
||
|
||
|
||
if (TransportHandle != NULL) {
|
||
ZwClose(TransportHandle);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserIssueTdiQuery(
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PCHAR Buffer,
|
||
IN ULONG BufferSize,
|
||
IN USHORT QueryType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will determine provider information about a transport.
|
||
|
||
Arguments:
|
||
|
||
IN PUNICODE_STRING TransportName - Supplies the name of the transport provider
|
||
|
||
|
||
Return Value:
|
||
|
||
Status of operation.
|
||
|
||
--*/
|
||
{
|
||
PIRP Irp;
|
||
PMDL Mdl;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
||
|
||
if (Irp == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
//
|
||
// Allocate an MDL to hold the provider info.
|
||
//
|
||
|
||
Mdl = IoAllocateMdl(Buffer, BufferSize,
|
||
FALSE,
|
||
FALSE,
|
||
NULL);
|
||
|
||
MmBuildMdlForNonPagedPool(Mdl);
|
||
|
||
TdiBuildQueryInformation(Irp, DeviceObject, FileObject,
|
||
NULL, NULL,
|
||
QueryType, Mdl);
|
||
|
||
status = BowserSubmitTdiRequest(FileObject, Irp);
|
||
|
||
IoFreeIrp(Irp);
|
||
|
||
ReturnStatus:
|
||
if (Mdl != NULL) {
|
||
IoFreeMdl(Mdl);
|
||
}
|
||
|
||
return(status);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
PTRANSPORT
|
||
BowserFindTransport (
|
||
PUNICODE_STRING TransportName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will locate a transport in the bowsers transport list.
|
||
|
||
Arguments:
|
||
|
||
PUNICODE_STRING TransportName - Supplies the name of the transport provider
|
||
|
||
|
||
Return Value:
|
||
|
||
PTRANSPORT - NULL if no transport was found, TRUE if transport was found.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY TransportEntry;
|
||
PTRANSPORT Transport = NULL;
|
||
PPAGED_TRANSPORT PagedTransport = NULL;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
try {
|
||
|
||
for (TransportEntry = BowserTransportHead.Flink ;
|
||
TransportEntry != &BowserTransportHead ;
|
||
TransportEntry = TransportEntry->Flink) {
|
||
|
||
PagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
|
||
|
||
if (RtlEqualUnicodeString(TransportName, &PagedTransport->TransportName, TRUE)) {
|
||
|
||
Transport = PagedTransport->NonPagedTransport;
|
||
|
||
BowserReferenceTransport( Transport );
|
||
|
||
try_return(Transport);
|
||
}
|
||
}
|
||
|
||
try_return(Transport = NULL);
|
||
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
ExReleaseResource (&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
return Transport;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserForEachTransport (
|
||
IN PTRANSPORT_ENUM_ROUTINE Routine,
|
||
IN OUT PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will enumerate the transports and call back the enum
|
||
routine provided with each transport.
|
||
|
||
Arguments:
|
||
|
||
IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
|
||
IN PIRP Irp - TDI request to submit.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of request.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY TransportEntry, NextEntry;
|
||
PTRANSPORT Transport = NULL;
|
||
PPAGED_TRANSPORT PagedTransport = NULL;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
for (TransportEntry = BowserTransportHead.Flink ;
|
||
TransportEntry != &BowserTransportHead ;
|
||
TransportEntry = NextEntry) {
|
||
|
||
PagedTransport = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT, GlobalNext);
|
||
|
||
Transport = PagedTransport->NonPagedTransport;
|
||
|
||
BowserReferenceTransport(Transport);
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
Status = (Routine)(Transport, Context);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
BowserDereferenceTransport(Transport);
|
||
|
||
return Status;
|
||
}
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
NextEntry = PagedTransport->GlobalNext.Flink;
|
||
|
||
BowserDereferenceTransport(Transport);
|
||
|
||
}
|
||
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserForEachTransportName(
|
||
IN PTRANSPORT Transport,
|
||
IN PTRANSPORT_NAME_ENUM_ROUTINE Routine,
|
||
IN OUT PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will enumerate the names associated with a transport
|
||
and call back the enum routine provided with each transport name.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of request.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY TransportEntry, NextEntry;
|
||
PTRANSPORT_NAME TransportName = NULL;
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = NULL;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
try {
|
||
|
||
for (TransportEntry = Transport->PagedTransport->NameChain.Flink ;
|
||
TransportEntry != &Transport->PagedTransport->NameChain ;
|
||
TransportEntry = NextEntry) {
|
||
|
||
PagedTransportName = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT_NAME, TransportNext);
|
||
|
||
TransportName = PagedTransportName->NonPagedTransportName;
|
||
|
||
Status = (Routine)(TransportName, Context);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
try_return(Status);
|
||
}
|
||
|
||
NextEntry = PagedTransportName->TransportNext.Flink;
|
||
|
||
}
|
||
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
BowserDeleteTransportNameByName(
|
||
IN PTRANSPORT Transport,
|
||
IN PUNICODE_STRING Name,
|
||
IN DGRECEIVER_NAME_TYPE NameType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes a transport name associated with a specific network.
|
||
|
||
Arguments:
|
||
|
||
IN PTRANSPORT Transport - Specifies the transport on which to delete the name.
|
||
IN PUNICODE_STRING Name - Specifies the transport name to delete.
|
||
IN DGRECEIVERNAMETYPE NameType - Specifies the name type of the name.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of request.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY TransportEntry, NextEntry;
|
||
PTRANSPORT_NAME TransportName = NULL;
|
||
PPAGED_TRANSPORT_NAME PagedTransportName = NULL;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
ExAcquireResourceExclusive(&BowserTransportDatabaseResource, TRUE);
|
||
|
||
try {
|
||
for (TransportEntry = Transport->PagedTransport->NameChain.Flink ;
|
||
TransportEntry != &Transport->PagedTransport->NameChain ;
|
||
TransportEntry = NextEntry) {
|
||
|
||
PagedTransportName = CONTAINING_RECORD(TransportEntry, PAGED_TRANSPORT_NAME, TransportNext);
|
||
|
||
TransportName = PagedTransportName->NonPagedTransportName;
|
||
|
||
ASSERT (TransportName->NameType == PagedTransportName->Name->NameType);
|
||
|
||
if ((TransportName->NameType == NameType) &&
|
||
RtlEqualUnicodeString(&PagedTransportName->Name->Name, Name, TRUE)) {
|
||
NextEntry = TransportEntry->Flink;
|
||
|
||
|
||
//
|
||
// Remove the TransportName from the list of transport names for
|
||
// this transport.
|
||
//
|
||
RemoveEntryList(&PagedTransportName->TransportNext);
|
||
PagedTransportName->TransportNext.Flink = NULL;
|
||
PagedTransportName->TransportNext.Blink = NULL;
|
||
|
||
|
||
//
|
||
// Since we delinked it, we need to dereference it.
|
||
//
|
||
Status = BowserDereferenceTransportName(TransportName);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
try_return(Status);
|
||
}
|
||
|
||
} else {
|
||
NextEntry = PagedTransportName->TransportNext.Flink;
|
||
}
|
||
|
||
}
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
ExReleaseResource(&BowserTransportDatabaseResource);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserSubmitTdiRequest (
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine submits a request to TDI and waits for it to complete.
|
||
|
||
Arguments:
|
||
|
||
IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
|
||
IN PIRP Irp - TDI request to submit.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Final status of request.
|
||
|
||
--*/
|
||
|
||
{
|
||
KEVENT Event;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
|
||
KeInitializeEvent (&Event, NotificationEvent, FALSE);
|
||
|
||
IoSetCompletionRoutine(Irp, BowserCompleteTdiRequest, &Event, TRUE, TRUE, TRUE);
|
||
|
||
//
|
||
// Submit the disconnect request
|
||
//
|
||
|
||
Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
|
||
|
||
//
|
||
// If it failed immediately, return now, otherwise wait.
|
||
//
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
dprintf(DPRT_TDI, ("BowserSubmitTdiRequest: submit request. Status = %X", Status));
|
||
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
return Status;
|
||
}
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
|
||
dprintf(DPRT_TDI, ("TDI request issued, waiting..."));
|
||
|
||
Status = KeWaitForSingleObject(&Event, // Object to wait on.
|
||
Executive, // Reason for waiting
|
||
KernelMode, // Processor mode
|
||
FALSE, // Alertable
|
||
NULL); // Timeout
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
dprintf(DPRT_TDI, ("Could not wait for operation to complete"));
|
||
KeBugCheck( 666 );
|
||
}
|
||
|
||
Status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
|
||
dprintf(DPRT_TDI, ("TDI request complete "));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
BowserCompleteTdiRequest (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completion routine for SubmitTdiRequest operation.
|
||
|
||
Arguments:
|
||
|
||
IN PDEVICE_OBJECT DeviceObject, - Supplies a pointer to the device object
|
||
IN PIRP Irp, - Supplies the IRP submitted
|
||
IN PVOID Context - Supplies a pointer to the kernel event to release
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of KeSetEvent
|
||
|
||
|
||
We return STATUS_MORE_PROCESSING_REQUIRED to prevent the IRP completion
|
||
code from processing this puppy any more.
|
||
|
||
--*/
|
||
|
||
{
|
||
DISCARDABLE_CODE( BowserDiscardableCodeSection );
|
||
dprintf(DPRT_TDI, ("CompleteTdiRequest: %lx\n", Context));
|
||
|
||
//
|
||
// Set the event to the Signalled state with 0 priority increment and
|
||
// indicate that we will not be blocking soon.
|
||
//
|
||
|
||
KeSetEvent((PKEVENT )Context, 0, FALSE);
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
// Quiet the compiler.
|
||
|
||
if (Irp || DeviceObject){};
|
||
}
|
||
|
||
typedef struct _SEND_DATAGRAM_CONTEXT {
|
||
PTDI_CONNECTION_INFORMATION ConnectionInformation;
|
||
PVOID Header;
|
||
BOOLEAN WaitForCompletion;
|
||
KEVENT Event;
|
||
} SEND_DATAGRAM_CONTEXT, *PSEND_DATAGRAM_CONTEXT;
|
||
|
||
|
||
NTSTATUS
|
||
BowserSendDatagram (
|
||
IN PTRANSPORT Transport,
|
||
IN PUNICODE_STRING Domain OPTIONAL,
|
||
IN DGRECEIVER_NAME_TYPE NameType,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferLength,
|
||
IN BOOLEAN WaitForCompletion,
|
||
IN PSTRING DestinationAddress OPTIONAL,
|
||
IN BOOLEAN IsHostAnnouncement
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends a datagram to the specified domain.
|
||
|
||
Arguments:
|
||
|
||
Domain - the name of the domain to send to.
|
||
Please note that the DOMAIN is padded with spaces and
|
||
terminated with the appropriate signature byte (00 or 07).
|
||
|
||
Buffer - the message to send.
|
||
|
||
BufferLength - the length of the buffer,
|
||
|
||
IsHostAnnouncement - True if the datagram is a host announcement
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - results of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG connectionInformationSize;
|
||
PIRP irp = NULL;
|
||
PMDL mdlAddress = NULL;
|
||
PSEND_DATAGRAM_CONTEXT context;
|
||
PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
|
||
// PTRANSPORT_NAME TComputerName;
|
||
ANSI_STRING AnsiString;
|
||
UCHAR IpxPacketType;
|
||
PFILE_OBJECT FileObject;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Ensure the computername has been registered for this transport
|
||
//
|
||
if ( Transport->ComputerName == NULL ) {
|
||
return STATUS_BAD_NETWORK_PATH;
|
||
}
|
||
|
||
//
|
||
// Ensure the Device and File object are known.
|
||
//
|
||
|
||
if (!FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
|
||
DeviceObject = Transport->ComputerName->DeviceObject;
|
||
FileObject = Transport->ComputerName->FileObject;
|
||
} else {
|
||
DeviceObject = Transport->IpxSocketDeviceObject;
|
||
FileObject = Transport->IpxSocketFileObject;
|
||
}
|
||
|
||
if ( DeviceObject == NULL || FileObject == NULL ) {
|
||
return STATUS_BAD_NETWORK_PATH;
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate a context describing this datagram send.
|
||
//
|
||
|
||
context = ALLOCATE_POOL(NonPagedPool, sizeof(SEND_DATAGRAM_CONTEXT), POOL_SENDDATAGRAM);
|
||
|
||
if ( context == NULL) {
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
connectionInformationSize = sizeof(TDI_CONNECTION_INFORMATION) +
|
||
max(sizeof(TA_NETBIOS_ADDRESS),
|
||
sizeof(TA_IPX_ADDRESS));
|
||
|
||
if (Domain == NULL) {
|
||
Domain = &Transport->PrimaryDomain->PagedTransportName->Name->Name;
|
||
}
|
||
|
||
if (FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
|
||
PSMB_IPX_NAME_PACKET NamePacket;
|
||
OEM_STRING NetBiosName;
|
||
|
||
context->Header = ALLOCATE_POOL(NonPagedPool, BufferLength + sizeof(SMB_IPX_NAME_PACKET), POOL_SENDDATAGRAM);
|
||
|
||
if ( context->Header == NULL ) {
|
||
FREE_POOL(context);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
NamePacket = context->Header;
|
||
|
||
RtlZeroMemory(NamePacket->Route, sizeof(NamePacket->Route));
|
||
|
||
NamePacket->Operation = SMB_IPX_MAILSLOT_SEND;
|
||
|
||
if (NameType == BrowserElection) {
|
||
if ( IsHostAnnouncement ) {
|
||
NamePacket->NameType = SMB_IPX_NAME_TYPE_BROWSER;
|
||
} else {
|
||
NamePacket->NameType = SMB_IPX_NAME_TYPE_WORKKGROUP;
|
||
}
|
||
} else if (NameType == ComputerName || NameType == AlternateComputerName ) {
|
||
NamePacket->NameType = SMB_IPX_NAME_TYPE_MACHINE;
|
||
} else {
|
||
NamePacket->NameType = SMB_IPX_NAME_TYPE_WORKKGROUP;
|
||
}
|
||
|
||
NamePacket->MessageId = 0;
|
||
|
||
NetBiosName.Length = 0;
|
||
NetBiosName.MaximumLength = SMB_IPX_NAME_LENGTH;
|
||
NetBiosName.Buffer = NamePacket->Name;
|
||
|
||
status = RtlUpcaseUnicodeStringToOemString(&NetBiosName, Domain, FALSE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
FREE_POOL( context->Header );
|
||
|
||
FREE_POOL( context );
|
||
|
||
return status;
|
||
}
|
||
|
||
RtlCopyMemory(&NetBiosName.Buffer[NetBiosName.Length], " ",
|
||
SMB_IPX_NAME_LENGTH-NetBiosName.Length);
|
||
|
||
NamePacket->Name[SMB_IPX_NAME_LENGTH-1] = WORKSTATION_SIGNATURE;
|
||
|
||
RtlCopyMemory(NamePacket->SourceName, ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName, SMB_IPX_NAME_LENGTH);
|
||
|
||
RtlCopyMemory((NamePacket+1), Buffer, BufferLength);
|
||
|
||
//
|
||
// We don't need the input buffer any more.
|
||
//
|
||
|
||
FREE_POOL(Buffer);
|
||
|
||
Buffer = context->Header;
|
||
BufferLength += sizeof(SMB_IPX_NAME_PACKET);
|
||
|
||
} else {
|
||
context->Header = Buffer;
|
||
}
|
||
|
||
context->ConnectionInformation = ALLOCATE_POOL(NonPagedPool,
|
||
connectionInformationSize, POOL_CONNECTINFO
|
||
);
|
||
|
||
if ( context->ConnectionInformation == NULL ) {
|
||
FREE_POOL(context->Header);
|
||
FREE_POOL(context);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
context->ConnectionInformation->UserDataLength = 0;
|
||
context->ConnectionInformation->UserData = NULL;
|
||
context->ConnectionInformation->OptionsLength = 0;
|
||
context->ConnectionInformation->Options = NULL;
|
||
|
||
AnsiString.Buffer = (PCHAR)(context->ConnectionInformation + 1);
|
||
AnsiString.MaximumLength = (USHORT)(connectionInformationSize - sizeof(TDI_CONNECTION_INFORMATION));
|
||
|
||
context->ConnectionInformation->RemoteAddress = AnsiString.Buffer;
|
||
|
||
context->WaitForCompletion = WaitForCompletion;
|
||
|
||
// ComputerName = Transport->ComputerName;
|
||
|
||
if (!ARGUMENT_PRESENT(DestinationAddress)) {
|
||
|
||
//
|
||
// If this is for our primary domain, and the request is destined
|
||
// for the master browser name, then stick in the address of our
|
||
// master browser if we know it.
|
||
//
|
||
|
||
if (RtlEqualMemory(Domain->Buffer, ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName, SMB_IPX_NAME_LENGTH) &&
|
||
( NameType == MasterBrowser ) &&
|
||
(Transport->PagedTransport->MasterBrowserAddress.Length != 0) ) {
|
||
|
||
//
|
||
// This is for our domain. If it's for our master browser
|
||
// and we know who that is, we're done - copy over the master's address
|
||
// and send it.
|
||
//
|
||
|
||
ASSERT (Transport->PagedTransport->MasterBrowserAddress.Length == sizeof(TA_IPX_ADDRESS));
|
||
|
||
RtlCopyMemory(context->ConnectionInformation->RemoteAddress,
|
||
Transport->PagedTransport->MasterBrowserAddress.Buffer,
|
||
Transport->PagedTransport->MasterBrowserAddress.Length);
|
||
|
||
//
|
||
// This is a directed packet, don't broadcast it.
|
||
//
|
||
IpxPacketType = IPX_DIRECTED_PACKET;
|
||
context->ConnectionInformation->OptionsLength = sizeof(IpxPacketType);
|
||
context->ConnectionInformation->Options = &IpxPacketType;
|
||
|
||
} else if (FlagOn(Transport->PagedTransport->Flags, DIRECT_HOST_IPX)) {
|
||
|
||
PTA_IPX_ADDRESS IpxAddress = (PTA_IPX_ADDRESS)AnsiString.Buffer;
|
||
|
||
IpxAddress->TAAddressCount = 1;
|
||
IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
|
||
IpxAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IPX;
|
||
|
||
IpxAddress->Address[0].Address[0].NetworkAddress = 0;
|
||
IpxAddress->Address[0].Address[0].NodeAddress[0] = 0xff;
|
||
IpxAddress->Address[0].Address[0].NodeAddress[1] = 0xff;
|
||
IpxAddress->Address[0].Address[0].NodeAddress[2] = 0xff;
|
||
IpxAddress->Address[0].Address[0].NodeAddress[3] = 0xff;
|
||
IpxAddress->Address[0].Address[0].NodeAddress[4] = 0xff;
|
||
IpxAddress->Address[0].Address[0].NodeAddress[5] = 0xff;
|
||
IpxAddress->Address[0].Address[0].Socket = SMB_IPX_MAILSLOT_SOCKET;
|
||
|
||
} else {
|
||
|
||
status = BowserBuildTransportAddress(&AnsiString,
|
||
Domain,
|
||
NameType,
|
||
Transport);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
FREE_POOL(context->ConnectionInformation);
|
||
FREE_POOL(context->Header);
|
||
FREE_POOL(context);
|
||
return status;
|
||
}
|
||
|
||
context->ConnectionInformation->RemoteAddressLength = AnsiString.Length;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// This is already correctly formatted, so just put it on the wire.
|
||
//
|
||
|
||
RtlCopyMemory(context->ConnectionInformation->RemoteAddress, DestinationAddress->Buffer, DestinationAddress->Length);
|
||
context->ConnectionInformation->RemoteAddressLength = DestinationAddress->Length;
|
||
|
||
//
|
||
// This is a directed packet, don't broadcast it.
|
||
//
|
||
IpxPacketType = IPX_DIRECTED_PACKET;
|
||
context->ConnectionInformation->OptionsLength = sizeof(IpxPacketType);
|
||
context->ConnectionInformation->Options = &IpxPacketType;
|
||
|
||
}
|
||
|
||
irp = IoAllocateIrp( DeviceObject->StackSize, TRUE);
|
||
|
||
if (irp == NULL) {
|
||
FREE_POOL(context->ConnectionInformation);
|
||
FREE_POOL(context->Header);
|
||
FREE_POOL(context);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
mdlAddress = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, NULL);
|
||
|
||
if (mdlAddress == NULL) {
|
||
FREE_POOL(context->ConnectionInformation);
|
||
FREE_POOL(context->Header);
|
||
FREE_POOL(context);
|
||
IoFreeIrp(irp);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
|
||
|
||
MmBuildMdlForNonPagedPool(mdlAddress);
|
||
|
||
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
|
||
ASSERT (KeGetCurrentIrql() == 0);
|
||
|
||
TdiBuildSendDatagram( irp,
|
||
DeviceObject,
|
||
FileObject,
|
||
CompleteSendDatagram,
|
||
context,
|
||
mdlAddress,
|
||
BufferLength,
|
||
context->ConnectionInformation);
|
||
|
||
|
||
status = IoCallDriver(DeviceObject, irp);
|
||
|
||
ASSERT (KeGetCurrentIrql() == 0);
|
||
|
||
if (WaitForCompletion) {
|
||
|
||
ASSERT (KeGetCurrentIrql() == 0);
|
||
if (status == STATUS_PENDING) {
|
||
status = KeWaitForSingleObject(&context->Event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
|
||
}
|
||
|
||
IoFreeMdl(irp->MdlAddress);
|
||
|
||
//
|
||
// Retrieve the status from the IRP.
|
||
//
|
||
|
||
status = irp->IoStatus.Status;
|
||
|
||
IoFreeIrp(irp);
|
||
|
||
FREE_POOL(context->ConnectionInformation);
|
||
|
||
FREE_POOL(context->Header);
|
||
|
||
FREE_POOL(context);
|
||
}
|
||
|
||
ASSERT (KeGetCurrentIrql() == 0);
|
||
|
||
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
|
||
|
||
return status;
|
||
|
||
} // BowserSendDatagram
|
||
|
||
NTSTATUS
|
||
CompleteSendDatagram (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Ctx
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completion routine for SubmitTdiRequest operation.
|
||
|
||
Arguments:
|
||
|
||
IN PDEVICE_OBJECT DeviceObject, - Supplies a pointer to the device object
|
||
IN PIRP Irp, - Supplies the IRP submitted
|
||
IN PVOID Context - Supplies a pointer to the kernel event to release
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of KeSetEvent
|
||
|
||
|
||
We return STATUS_MORE_PROCESSING_REQUIRED to prevent the IRP completion
|
||
code from processing this puppy any more.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSEND_DATAGRAM_CONTEXT Context = Ctx;
|
||
|
||
DISCARDABLE_CODE( BowserDiscardableCodeSection );
|
||
|
||
dprintf(DPRT_TDI, ("CompleteTdiRequest: %lx\n", Context));
|
||
|
||
if (Context->WaitForCompletion) {
|
||
|
||
//
|
||
// Set the event to the Signalled state with 0 priority increment and
|
||
// indicate that we will not be blocking soon.
|
||
//
|
||
|
||
KeSetEvent(&Context->Event, 0, FALSE);
|
||
|
||
} else {
|
||
FREE_POOL(Context->ConnectionInformation);
|
||
|
||
FREE_POOL(Context->Header);
|
||
|
||
FREE_POOL(Context);
|
||
|
||
IoFreeMdl(Irp->MdlAddress);
|
||
|
||
IoFreeIrp(Irp);
|
||
|
||
}
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
BowserSendSecondClassMailslot (
|
||
IN PTRANSPORT Transport,
|
||
IN PUNICODE_STRING Domain OPTIONAL,
|
||
IN DGRECEIVER_NAME_TYPE NameType,
|
||
IN PVOID Message,
|
||
IN ULONG MessageLength,
|
||
IN BOOLEAN WaitForCompletion,
|
||
IN PCHAR mailslotNameData,
|
||
IN PSTRING DestinationAddress OPTIONAL
|
||
)
|
||
{
|
||
ULONG dataSize;
|
||
ULONG transactionDataSize;
|
||
ULONG smbSize;
|
||
PSMB_HEADER header;
|
||
PSMB_TRANSACT_MAILSLOT parameters;
|
||
PSZ mailslotName;
|
||
ULONG mailslotNameLength;
|
||
PSZ domainInData;
|
||
PVOID message;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// Determine the sizes of various fields that will go in the SMB
|
||
// and the total size of the SMB.
|
||
//
|
||
|
||
mailslotNameLength = strlen( mailslotNameData );
|
||
|
||
transactionDataSize = MessageLength;
|
||
dataSize = mailslotNameLength + 1 + transactionDataSize;
|
||
smbSize = sizeof(SMB_HEADER) + sizeof(SMB_TRANSACT_MAILSLOT) - 1 + dataSize;
|
||
|
||
header = ALLOCATE_POOL( NonPagedPool, smbSize, POOL_MAILSLOT_HEADER );
|
||
if ( header == NULL ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Fill in the header. Most of the fields don't matter and are
|
||
// zeroed.
|
||
//
|
||
|
||
RtlZeroMemory( header, smbSize );
|
||
|
||
header->Protocol[0] = 0xFF;
|
||
header->Protocol[1] = 'S';
|
||
header->Protocol[2] = 'M';
|
||
header->Protocol[3] = 'B';
|
||
header->Command = SMB_COM_TRANSACTION;
|
||
|
||
//
|
||
// Get the pointer to the params and fill them in.
|
||
//
|
||
|
||
parameters = (PSMB_TRANSACT_MAILSLOT)( header + 1 );
|
||
mailslotName = (PSZ)( parameters + 1 ) - 1;
|
||
domainInData = mailslotName + mailslotNameLength + 1;
|
||
message = domainInData;
|
||
|
||
parameters->WordCount = 0x11;
|
||
SmbPutUshort( ¶meters->TotalDataCount, (USHORT)transactionDataSize );
|
||
SmbPutUlong( ¶meters->Timeout, 0x3E8 ); // !!! fix
|
||
SmbPutUshort( ¶meters->DataCount, (USHORT)transactionDataSize );
|
||
SmbPutUshort(
|
||
¶meters->DataOffset,
|
||
(USHORT)( (ULONG)message - (ULONG)header )
|
||
);
|
||
parameters->SetupWordCount = 3;
|
||
SmbPutUshort( ¶meters->Opcode, MS_WRITE_OPCODE );
|
||
SmbPutUshort( ¶meters->Priority, 1);
|
||
SmbPutUshort( ¶meters->Class, 2 );
|
||
SmbPutUshort( ¶meters->ByteCount, (USHORT)dataSize );
|
||
|
||
RtlCopyMemory( mailslotName, mailslotNameData, mailslotNameLength + 1 );
|
||
RtlCopyMemory( message, Message, MessageLength );
|
||
|
||
//
|
||
// Send the actual mailslot message.
|
||
//
|
||
|
||
status = BowserSendDatagram( Transport,
|
||
Domain,
|
||
NameType,
|
||
header,
|
||
smbSize,
|
||
WaitForCompletion,
|
||
DestinationAddress,
|
||
(BOOLEAN)(((PHOST_ANNOUNCE_PACKET)Message)->AnnounceType == LocalMasterAnnouncement) );
|
||
|
||
return status;
|
||
|
||
} // BowserSendSecondClassMailslot
|
||
|
||
|
||
NTSTATUS
|
||
BowserSendRequestAnnouncement(
|
||
IN PUNICODE_STRING DestinationName,
|
||
IN DGRECEIVER_NAME_TYPE NameType,
|
||
IN PTRANSPORT Transport
|
||
)
|
||
{
|
||
REQUEST_ANNOUNCE_PACKET AnnounceRequest;
|
||
ULONG AnnouncementRequestLength;
|
||
OEM_STRING AnsiServerName;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
AnnounceRequest.Type = AnnouncementRequest;
|
||
|
||
AnnounceRequest.RequestAnnouncement.Flags = 0;
|
||
|
||
AnsiServerName.Buffer = AnnounceRequest.RequestAnnouncement.Reply;
|
||
|
||
AnsiServerName.MaximumLength = sizeof(REQUEST_ANNOUNCE_PACKET) - FIELD_OFFSET(REQUEST_ANNOUNCE_PACKET, RequestAnnouncement.Reply);
|
||
|
||
Status = RtlUnicodeStringToOemString(&AnsiServerName, &Transport->ComputerName->PagedTransportName->Name->Name,
|
||
FALSE);
|
||
|
||
AnnouncementRequestLength = FIELD_OFFSET(REQUEST_ANNOUNCE_PACKET, RequestAnnouncement.Reply) +
|
||
AnsiServerName.Length + 1;
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
Status = BowserSendSecondClassMailslot(Transport,
|
||
DestinationName,
|
||
NameType,
|
||
&AnnounceRequest,
|
||
AnnouncementRequestLength,
|
||
TRUE,
|
||
MAILSLOT_BROWSER_NAME,
|
||
NULL);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
VOID
|
||
BowserpInitializeTdi (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the global variables used in the transport
|
||
package.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Initialize the Transport list chain
|
||
//
|
||
|
||
InitializeListHead(&BowserTransportHead);
|
||
|
||
ExInitializeResource(&BowserTransportDatabaseResource);
|
||
|
||
KeInitializeSpinLock(&BowserTransportMasterNameSpinLock);
|
||
}
|
||
|
||
VOID
|
||
BowserpUninitializeTdi (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the global variables used in the transport
|
||
package.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
ASSERT (IsListEmpty(&BowserTransportHead));
|
||
|
||
ExDeleteResource(&BowserTransportDatabaseResource);
|
||
|
||
}
|