NT4/private/ntos/bowser/fsctl.c
2020-09-30 17:12:29 +02:00

3221 lines
83 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
fsctl.c
Abstract:
This module implements the NtDeviceIoControlFile API's for the NT datagram
receiver (bowser).
Author:
Larry Osterman (larryo) 6-May-1991
Revision History:
6-May-1991 larryo
Created
--*/
#include "precomp.h"
#pragma hdrstop
NTSTATUS
BowserCommonDeviceIoControlFile (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
StartBowser (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
);
NTSTATUS
BowserEnumTransports (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN PULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
);
NTSTATUS
EnumNames (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN PULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
);
NTSTATUS
BowserBindToTransport (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
);
NTSTATUS
UnbindFromTransport (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
);
NTSTATUS
AddBowserName (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
);
NTSTATUS
StopBowser (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
);
NTSTATUS
DeleteName (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
);
NTSTATUS
EnumServers (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN PULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
);
NTSTATUS
GetHint (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN OUT PULONG InputBufferLength
);
NTSTATUS
GetLogonStatusRequest (
IN PIRP Irp
);
NTSTATUS
WaitForBrowserRoleChange (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
WaitForNewMaster (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
HandleBecomeBackup (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
BecomeMaster (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
WaitForMasterAnnounce (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
WriteMailslot (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength
);
NTSTATUS
UpdateStatus (
IN PIRP Irp,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
WaitForBrowserRequest (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
GetBrowserServerList(
IN PIRP Irp,
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN OUT PULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
);
NTSTATUS
QueryStatistics(
IN PIRP Irp,
OUT PBOWSER_STATISTICS OutputBuffer,
IN OUT PULONG OutputBufferLength
);
NTSTATUS
ResetStatistics(
VOID
);
NTSTATUS
BowserIpAddressChanged(
IN PLMDR_REQUEST_PACKET InputBuffer
);
NTSTATUS
EnableDisableTransport (
IN PLMDR_REQUEST_PACKET InputBuffer
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, BowserCommonDeviceIoControlFile)
#pragma alloc_text(PAGE, BowserFspDeviceIoControlFile)
#pragma alloc_text(PAGE, BowserFsdDeviceIoControlFile)
#pragma alloc_text(PAGE, StartBowser)
#pragma alloc_text(PAGE, BowserEnumTransports)
#pragma alloc_text(PAGE, EnumNames)
#pragma alloc_text(PAGE, BowserBindToTransport)
#pragma alloc_text(PAGE, UnbindFromTransport)
#pragma alloc_text(PAGE, AddBowserName)
#pragma alloc_text(PAGE, StopBowser)
#pragma alloc_text(PAGE, DeleteName)
#pragma alloc_text(PAGE, EnumServers)
#pragma alloc_text(PAGE, GetHint)
#pragma alloc_text(PAGE, GetLogonStatusRequest)
#pragma alloc_text(PAGE, WaitForBrowserRoleChange)
#pragma alloc_text(PAGE, HandleBecomeBackup)
#pragma alloc_text(PAGE, BecomeMaster)
#pragma alloc_text(PAGE, WaitForMasterAnnounce)
#pragma alloc_text(PAGE, WriteMailslot)
#pragma alloc_text(PAGE, UpdateStatus)
#pragma alloc_text(PAGE, BowserStopProcessingAnnouncements)
#pragma alloc_text(PAGE, WaitForBrowserRequest)
#pragma alloc_text(PAGE, GetBrowserServerList)
#pragma alloc_text(PAGE, WaitForNewMaster)
#pragma alloc_text(PAGE, BowserIpAddressChanged)
#pragma alloc_text(PAGE, EnableDisableTransport)
#pragma alloc_text(PAGE4BROW, QueryStatistics)
#pragma alloc_text(PAGE4BROW, ResetStatistics)
#if DBG
#pragma alloc_text(PAGE, BowserDebugCall)
#endif
#endif
NTSTATUS
BowserFspDeviceIoControlFile (
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called when the last handle to the NT Bowser device
driver is closed.
Arguments:
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
IN PIRP Irp - Supplies an IRP for the create request.
Return Value:
NTSTATUS - Final Status of operation
--*/
{
NTSTATUS Status;
PAGED_CODE();
Status = BowserCommonDeviceIoControlFile(TRUE,
FALSE,
DeviceObject,
Irp);
return Status;
}
NTSTATUS
BowserFsdDeviceIoControlFile (
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called when the last handle to the NT Bowser device
driver is closed.
Arguments:
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
IN PIRP Irp - Supplies an IRP for the create request.
Return Value:
NTSTATUS - Final Status of operation
--*/
{
NTSTATUS Status;
PAGED_CODE();
#ifndef PRODUCT1
FsRtlEnterFileSystem();
#endif
Status = BowserCommonDeviceIoControlFile(IoIsOperationSynchronous(Irp),
TRUE,
DeviceObject,
Irp);
#ifndef PRODUCT1
FsRtlExitFileSystem();
#endif
return Status;
}
NTSTATUS
BowserCommonDeviceIoControlFile (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called when the last handle to the NT Bowser device
driver is closed.
Arguments:
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
IN PIRP Irp - Supplies an IRP for the create request.
Return Value:
NTSTATUS - Final Status of operation
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PVOID InputBuffer;
ULONG InputBufferLength;
PVOID OutputBuffer;
ULONG OutputBufferLength;
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
ULONG MinorFunction = IrpSp->MinorFunction;
PAGED_CODE();
try {
//
// Before we call the worker functions, prep the parameters to those
// functions.
//
//
// The lengths of the various buffers are easy to find, they're in the
// Irp stack location.
//
OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
//
// The input buffer is either in Irp->AssociatedIrp.SystemBuffer, or
// in the Type3InputBuffer for type 3 IRP's.
//
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// If we are in the FSD, then the input buffer is in Type3InputBuffer
// on type 3 api's, not in SystemBuffer.
//
if (InputBuffer == NULL) {
//
// This had better be a type 3 IOCTL, or the input buffer had
// better be 0 length.
//
ASSERT (((IoControlCode & 3) == METHOD_NEITHER) ||
(IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0));
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) &&
(IoControlCode & 3) == METHOD_NEITHER) {
//
// We had better be in the FSD.
//
ASSERT (InFsd);
InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
}
}
//
// The output buffer is either probed/locked in memory, or is
// available in the input buffer.
//
try {
BowserMapUsersBuffer(Irp, &OutputBuffer, OutputBufferLength);
} except (EXCEPTION_EXECUTE_HANDLER) {
return Status = GetExceptionCode();
}
switch (MinorFunction) {
//
// The NT redirector does not support local physical media, all
// such IoControlFile requests are unsupported.
//
case IRP_MN_USER_FS_REQUEST:
switch (IoControlCode) {
case IOCTL_LMDR_START:
Status = StartBowser(Wait, InFsd, DeviceObject, InputBuffer, InputBufferLength);
break;
case IOCTL_LMDR_STOP:
Status = StopBowser(Wait, InFsd, DeviceObject, InputBuffer, InputBufferLength);
break;
case IOCTL_LMDR_BIND_TO_TRANSPORT:
Status = BowserBindToTransport(Wait, InFsd, InputBuffer, InputBufferLength);
break;
case IOCTL_LMDR_UNBIND_FROM_TRANSPORT:
Status = UnbindFromTransport(Wait, InFsd, InputBuffer, InputBufferLength);
break;
case IOCTL_LMDR_ENUMERATE_TRANSPORTS:
Status = BowserEnumTransports(Wait, InFsd,
InputBuffer, &InputBufferLength,
OutputBuffer, OutputBufferLength,
(PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
break;
case IOCTL_LMDR_ENUMERATE_NAMES:
Status = EnumNames(Wait, InFsd,
InputBuffer, &InputBufferLength,
OutputBuffer, OutputBufferLength,
(PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
break;
case IOCTL_LMDR_ADD_NAME:
case IOCTL_LMDR_ADD_NAME_DOM:
Status = AddBowserName(Wait, InFsd, InputBuffer, InputBufferLength);
break;
case IOCTL_LMDR_DELETE_NAME:
case IOCTL_LMDR_DELETE_NAME_DOM:
Status = DeleteName (Wait, InFsd, InputBuffer, InputBufferLength);
break;
case IOCTL_LMDR_ENUMERATE_SERVERS:
Status = EnumServers(Wait, InFsd,
InputBuffer, &InputBufferLength,
OutputBuffer, OutputBufferLength,
(PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
break;
case IOCTL_LMDR_GET_HINT_SIZE:
Status = GetHint(Wait, InFsd, InputBuffer, &InputBufferLength);
break;
case IOCTL_LMDR_GET_LOGONSTATUS_REQUEST:
Status = GetLogonStatusRequest(Irp);
break;
case IOCTL_LMDR_GET_BROWSER_SERVER_LIST:
Status = GetBrowserServerList(Irp, Wait, InFsd,
InputBuffer, &InputBufferLength,
OutputBuffer, OutputBufferLength,
(PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
break;
case IOCTL_LMDR_GET_MASTER_NAME:
Status = GetMasterName(Irp, Wait, InFsd,
InputBuffer);
break;
case IOCTL_LMDR_BECOME_BACKUP:
Status = HandleBecomeBackup(Irp, InputBuffer);
break;
case IOCTL_LMDR_BECOME_MASTER:
Status = BecomeMaster(Irp, InputBuffer);
break;
case IOCTL_LMDR_WAIT_FOR_BROWSER_REQUEST:
Status = WaitForBrowserRequest(Irp, InputBuffer);
break;
case IOCTL_LMDR_WAIT_FOR_MASTER_ANNOUNCE:
Status = WaitForMasterAnnounce(Irp, InputBuffer);
break;
case IOCTL_LMDR_WRITE_MAILSLOT:
Status = WriteMailslot(Irp, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength);
break;
case IOCTL_LMDR_UPDATE_STATUS:
Status = UpdateStatus(Irp, InFsd, InputBuffer);
break;
case IOCTL_LMDR_CHANGE_ROLE:
Status = WaitForBrowserRoleChange(Irp, InputBuffer);
break;
case IOCTL_LMDR_NEW_MASTER_NAME:
Status = WaitForNewMaster(Irp, InputBuffer);
break;
case IOCTL_LMDR_QUERY_STATISTICS:
Status = QueryStatistics(Irp, OutputBuffer, &OutputBufferLength);
InputBufferLength = OutputBufferLength;
break;
case IOCTL_LMDR_RESET_STATISTICS:
Status = ResetStatistics();
break;
case IOCTL_LMDR_NETLOGON_MAILSLOT_READ:
Status = NetlogonMailslotRead( Irp, OutputBufferLength );
break;
case IOCTL_LMDR_NETLOGON_MAILSLOT_ENABLE:
Status = NetlogonMailslotEnable( InputBuffer );
break;
case IOCTL_LMDR_IP_ADDRESS_CHANGED:
Status = BowserIpAddressChanged( InputBuffer );
break;
case IOCTL_LMDR_ENABLE_DISABLE_TRANSPORT:
Status = EnableDisableTransport( InputBuffer );
break;
#if DBG
case IOCTL_LMDR_DEBUG_CALL:
if (InFsd) {
Status = STATUS_PENDING;
} else {
Status = BowserDebugCall(InputBuffer, InputBufferLength);
}
break;
#endif
default:
dprintf(DPRT_FSCTL, ("Unknown IoControlFile %d\n", MinorFunction));
Status = STATUS_NOT_IMPLEMENTED;
break;
}
break;
//
// All other IoControlFile API's
//
default:
dprintf(DPRT_FSCTL, ("Unknown IoControlFile %d\n", MinorFunction));
Status = STATUS_NOT_IMPLEMENTED;
break;
}
if (Status != STATUS_PENDING) {
//
// Return the size of the input buffer to the caller.
//
Irp->IoStatus.Information = InputBufferLength;
}
} finally {
if (Status == STATUS_PENDING) {
//
// If this is one of the longterm FsControl APIs, they are
// not to be processed in the FSP, they should just be returned
// to the caller with STATUS_PENDING.
//
if ((MinorFunction == IRP_MN_USER_FS_REQUEST) &&
((IoControlCode == IOCTL_LMDR_GET_MASTER_NAME) ||
(IoControlCode == IOCTL_LMDR_BECOME_BACKUP) ||
(IoControlCode == IOCTL_LMDR_BECOME_MASTER) ||
(IoControlCode == IOCTL_LMDR_CHANGE_ROLE) ||
(IoControlCode == IOCTL_LMDR_WAIT_FOR_BROWSER_REQUEST) ||
(IoControlCode == IOCTL_LMDR_NEW_MASTER_NAME) ||
(IoControlCode == IOCTL_LMDR_WAIT_FOR_MASTER_ANNOUNCE) ||
(IoControlCode == IOCTL_LMDR_NETLOGON_MAILSLOT_READ) ||
(IoControlCode == IOCTL_LMDR_GET_LOGONSTATUS_REQUEST))) {
// return Status;
} else {
ASSERT (InFsd);
if ((IoControlCode & 3) == METHOD_NEITHER) {
Status = BowserConvertType3IoControlToType2IoControl(Irp, IrpSp);
}
if (NT_SUCCESS(Status)) {
PLMDR_REQUEST_PACKET RequestPacket;
RequestPacket = Irp->AssociatedIrp.SystemBuffer;
if ((RequestPacket->Version == LMDR_REQUEST_PACKET_VERSION) &&
(RequestPacket->TransportName.Length) != 0) {
PCHAR InputBuffer;
ULONG InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
if ((IoControlCode & 3) == METHOD_NEITHER) {
InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
//
// There is a transport name associated with this request.
//
if (((PCHAR)RequestPacket->TransportName.Buffer > InputBuffer) &&
(((PCHAR)RequestPacket->TransportName.Buffer+RequestPacket->TransportName.Length) <= InputBuffer+InputBufferLength)) {
//
// If the transport name is less than the start of the
// input buffer, convert it.
//
RequestPacket->TransportName.Buffer = (PWSTR)
(((ULONG)Irp->AssociatedIrp.SystemBuffer)+
(((ULONG)RequestPacket->TransportName.Buffer) -
((ULONG)InputBuffer)));
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
}
if (NT_SUCCESS(Status)) {
Status = BowserFsdPostToFsp(DeviceObject, Irp);
}
}
if (Status != STATUS_PENDING) {
BowserCompleteRequest(Irp, Status);
}
}
} else {
BowserCompleteRequest(Irp, Status);
}
}
dprintf(DPRT_FSCTL, ("Returning status: %X\n", Status));
return Status;
}
NTSTATUS
StartBowser (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Initialize request "));
if (!ExAcquireResourceExclusive(&BowserDataResource, Wait)) {
return STATUS_PENDING;
}
try {
if (BowserData.Initialized == TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
try_return(Status = STATUS_REDIRECTOR_STARTED);
}
//
// Load a pointer to the users input buffer into InputBuffer
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (InputBufferLength != sizeof(LMDR_REQUEST_PACKET)) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
BowserData.IllegalDatagramThreshold = InputBuffer->Parameters.Start.IllegalDatagramThreshold;
BowserData.EventLogResetFrequency = InputBuffer->Parameters.Start.EventLogResetFrequency;
BowserData.NumberOfMailslotBuffers = InputBuffer->Parameters.Start.NumberOfMailslotBuffers;
BowserData.NumberOfServerAnnounceBuffers = InputBuffer->Parameters.Start.NumberOfServerAnnounceBuffers;
BowserLogElectionPackets = InputBuffer->Parameters.Start.LogElectionPackets;
Status = BowserpInitializeAnnounceTable();
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
BowserData.Initialized = TRUE;
//
// Now that we know the browser parameters, we can kick off the
// browser timer...
//
IoStartTimer((PDEVICE_OBJECT )DeviceObject);
KeQuerySystemTime(&BowserStartTime);
RtlZeroMemory(&BowserStatistics, sizeof(BOWSER_STATISTICS));
KeQuerySystemTime(&BowserStatistics.StartTime);
KeInitializeSpinLock(&BowserStatisticsLock);
try_return(Status = STATUS_SUCCESS);
try_exit:NOTHING;
} finally {
ExReleaseResource(&BowserDataResource);
}
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
StopBowser (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
This routine sets the username for the NT redirector.
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN PBOWSER_FS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
IN PIRP Irp, - Io Request Packet for request
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Initialize request "));
if (!ExAcquireResourceExclusive(&BowserDataResource, Wait)) {
return STATUS_PENDING;
}
try {
if (BowserData.Initialized != TRUE) {
try_return(Status = STATUS_REDIRECTOR_NOT_STARTED);
}
//
// Load a pointer to the users input buffer into InputBuffer
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (InputBufferLength != sizeof(LMDR_REQUEST_PACKET)) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (InFsd) {
try_return(Status = STATUS_PENDING);
}
BowserData.Initialized = FALSE;
Status = BowserUnbindFromAllTransports();
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
Status = BowserDeleteAllNames();
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
Status = BowserpUninitializeAnnounceTable();
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
//
// Now that we know the browser parameters, we can kick off the
// browser timer...
//
IoStopTimer((PDEVICE_OBJECT )DeviceObject);
try_return(Status = STATUS_SUCCESS);
try_exit:NOTHING;
} finally {
ExReleaseResource(&BowserDataResource);
}
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
BowserBindToTransport (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
UNICODE_STRING TransportName;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Bind to transport "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
//
// We are about to perform the actual bind, if we cannot
// block the users thread, pass this request to the FSP
// to have it perform the operation.
//
if (InFsd) {
return STATUS_PENDING;
}
RtlInitUnicodeString(&TransportName, NULL);
TransportName.MaximumLength = TransportName.Length = (USHORT )
InputBuffer->Parameters.Bind.TransportNameLength;
TransportName.Buffer = InputBuffer->Parameters.Bind.TransportName;
dprintf(DPRT_FSCTL, ("\"%Z\"", &TransportName));
Status = BowserTdiAllocateTransport(&TransportName);
ReturnStatus:
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InputBufferLength);
}
NTSTATUS
UnbindFromTransport (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
UNICODE_STRING TransportName;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Unbind from transport "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
//
// We are about to perform the actual bind, if we cannot
// block the users thread, pass this request to the FSP
// to have it perform the operation.
//
if (InFsd) {
return STATUS_PENDING;
}
RtlInitUnicodeString(&TransportName, NULL);
TransportName.MaximumLength = TransportName.Length = (USHORT )
InputBuffer->Parameters.Bind.TransportNameLength;
TransportName.Buffer = InputBuffer->Parameters.Bind.TransportName;
dprintf(DPRT_FSCTL, ("\"%wZ\"", &TransportName));
Status = BowserFreeTransportByName(&TransportName);
ReturnStatus:
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InputBufferLength);
}
NTSTATUS
BowserEnumTransports (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN PULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
)
/*++
Routine Description:
This routine enumerates the transports bound into the bowser.
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT PULONG OutputBufferLength
Return Value:
NTSTATUS - Status of operation.
--*/
{
NTSTATUS Status;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: EnumerateTransports "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (*InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (InputBuffer->Type != EnumerateXports) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (OutputBufferLength < sizeof(LMDR_TRANSPORT_LIST)) {
Status = STATUS_BUFFER_TOO_SMALL;
}
Status = BowserEnumerateTransports(OutputBuffer,
OutputBufferLength,
&InputBuffer->Parameters.EnumerateTransports.EntriesRead,
&InputBuffer->Parameters.EnumerateTransports.TotalEntries,
&InputBuffer->Parameters.EnumerateTransports.TotalBytesNeeded,
OutputBufferDisplacement);
*InputBufferLength = sizeof(LMDR_REQUEST_PACKET);
ReturnStatus:
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
EnumNames (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN PULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
)
/*++
Routine Description:
This routine enumerates the names bound into the bowser.
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT PULONG OutputBufferLength
Return Value:
NTSTATUS - Status of operation.
--*/
{
NTSTATUS Status;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: EnumerateNames "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (*InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (InputBuffer->Type != EnumerateNames) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (OutputBufferLength < sizeof(DGRECEIVE_NAMES)) {
Status = STATUS_BUFFER_TOO_SMALL;
}
Status = BowserEnumerateNames(OutputBuffer,
OutputBufferLength,
&InputBuffer->Parameters.EnumerateTransports.EntriesRead,
&InputBuffer->Parameters.EnumerateTransports.TotalEntries,
&InputBuffer->Parameters.EnumerateTransports.TotalBytesNeeded,
OutputBufferDisplacement);
*InputBufferLength = sizeof(LMDR_REQUEST_PACKET);
ReturnStatus:
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
DeleteName (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
UNICODE_STRING Name;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Delete Name "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
//
// We are about to perform the actual bind, if we cannot
// block the users thread, pass this request to the FSP
// to have it perform the operation.
//
if (InFsd) {
return STATUS_PENDING;
}
RtlInitUnicodeString(&Name, NULL);
Name.MaximumLength = Name.Length = (USHORT )
InputBuffer->Parameters.AddDelName.DgReceiverNameLength;
Name.Buffer = InputBuffer->Parameters.AddDelName.Name;
dprintf(DPRT_FSCTL, ("\"%Z\"", &Name));
Status = BowserDeleteNameByName(&Name, InputBuffer->Parameters.AddDelName.Type);
ReturnStatus:
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InputBufferLength);
}
NTSTATUS
EnumServers (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN PULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT PULONG OutputBufferLength
Return Value:
NTSTATUS - Status of operation.
--*/
{
NTSTATUS Status;
UNICODE_STRING DomainName;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: EnumerateServers "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (*InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (InputBuffer->Type != EnumerateServers) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (InputBuffer->Level != 100 && InputBuffer->Level != 101) {
Status = STATUS_INVALID_LEVEL;
}
if (OutputBufferLength < sizeof(SERVER_INFO_100)) {
Status = STATUS_BUFFER_TOO_SMALL;
}
if (InputBuffer->Level == 101 && OutputBufferLength < sizeof(SERVER_INFO_101)) {
Status = STATUS_BUFFER_TOO_SMALL;
}
if (InputBuffer->Parameters.EnumerateServers.DomainNameLength != 0) {
DomainName.Buffer = InputBuffer->Parameters.EnumerateServers.DomainName;
DomainName.Length = (USHORT )InputBuffer->Parameters.EnumerateServers.DomainNameLength;
}
Status = BowserEnumerateServers( InputBuffer->Level, &InputBuffer->LogonId,
&InputBuffer->Parameters.EnumerateServers.ResumeHandle,
InputBuffer->Parameters.EnumerateServers.ServerType,
(InputBuffer->TransportName.Length != 0 ? &InputBuffer->TransportName : NULL),
(InputBuffer->Parameters.EnumerateServers.DomainNameLength != 0 ? &DomainName : NULL),
OutputBuffer,
OutputBufferLength,
&InputBuffer->Parameters.EnumerateServers.EntriesRead,
&InputBuffer->Parameters.EnumerateServers.TotalEntries,
&InputBuffer->Parameters.EnumerateServers.TotalBytesNeeded,
OutputBufferDisplacement);
*InputBufferLength = sizeof(LMDR_REQUEST_PACKET);
ReturnStatus:
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
AddBowserName (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
UNICODE_STRING Name;
PTRANSPORT Transport = NULL;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Bind to transport "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
//
// We are about to perform the actual bind, if we cannot
// block the users thread, pass this request to the FSP
// to have it perform the operation.
//
if (InFsd) {
return STATUS_PENDING;
}
BowserFspProcess = IoGetCurrentProcess();
RtlInitUnicodeString(&Name, NULL);
Name.MaximumLength = Name.Length = (USHORT )
InputBuffer->Parameters.AddDelName.DgReceiverNameLength;
Name.Buffer = InputBuffer->Parameters.AddDelName.Name;
dprintf(DPRT_FSCTL, ("\"%Z\"", &Name));
if (InputBuffer->TransportName.Length != 0) {
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto ReturnStatus;
}
}
Status = BowserAllocateName(&Name,
InputBuffer->Parameters.AddDelName.Type,
Transport);
ReturnStatus:
if (Transport != NULL) {
BowserDereferenceTransport(Transport);
}
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InputBufferLength);
}
NTSTATUS
GetHint (
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN OUT PULONG InputBufferLength
)
/*++
Routine Description:
This routine adds a reference to a file object created with .
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Initialize request "));
if (!ExAcquireResourceShared(&BowserDataResource, Wait)) {
return STATUS_PENDING;
}
try {
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
try_return(Status = STATUS_REDIRECTOR_NOT_STARTED);
}
//
// Load a pointer to the users input buffer into InputBuffer
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (*InputBufferLength != sizeof(LMDR_REQUEST_PACKET)) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
InputBuffer->Parameters.GetHintSize.ServerInfoHintSize =
BowserGetAnnounceTableSize();
InputBuffer->Parameters.GetHintSize.DGReceiverNamesHintSize = 0;
try_return(Status = STATUS_SUCCESS);
try_exit:NOTHING;
} finally {
ExReleaseResource(&BowserDataResource);
}
return Status;
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
GetLogonStatusRequest (
IN PIRP Irp
)
/*++
Routine Description:
This routine will queue a request that will complete when a request
announcement network request is received.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
#if 0
NTSTATUS Status;
#endif
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
GetBrowserServerList(
IN PIRP Irp,
IN BOOLEAN Wait,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN OUT PULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength,
IN ULONG OutputBufferDisplacement
)
/*++
Routine Description:
This routine will return the list of browser servers for the specified
net on the specified domain.
Arguments:
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN OUT PULONG OutputBufferLength
Return Value:
NTSTATUS - Status of operation.
--*/
{
NTSTATUS Status;
UNICODE_STRING DomainName;
PTRANSPORT Transport = NULL;
ULONG BrowserServerListLength;
PWSTR *BrowserServerList;
BOOLEAN IsPrimaryDomain = FALSE;
BOOLEAN TransportBrowserListAcquired = FALSE;
PVOID OutputBufferEnd = (PCHAR)OutputBuffer + OutputBufferLength;
PPAGED_TRANSPORT PagedTransport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: GetBrowserServerList "));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser not started.\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
try {
try {
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (*InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (InputBuffer->TransportName.Length == 0 ||
InputBuffer->TransportName.Buffer == NULL) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
if (InputBuffer->Parameters.GetBrowserServerList.DomainNameLength != 0) {
DomainName.Buffer = InputBuffer->Parameters.GetBrowserServerList.DomainName;
DomainName.Length = (USHORT )InputBuffer->Parameters.GetBrowserServerList.DomainNameLength;
} else {
DomainName.Length = 0;
DomainName.Buffer = NULL;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
try_return(Status = GetExceptionCode());
}
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
try_return(Status = STATUS_OBJECT_NAME_NOT_FOUND);
}
PagedTransport = Transport->PagedTransport;
if (!ExAcquireResourceShared(&Transport->BrowserServerListResource, Wait)) {
try_return(Status = STATUS_PENDING);
}
TransportBrowserListAcquired = TRUE;
//
// If this request is for the primary domain and there are no entries
// in the cached list, or if it is not for the primary domain, or
// if we are supposed to force a rescan of the list, get the list
// from the master for that domain..
//
if ((DomainName.Length == 0) ||
((Transport->PrimaryDomain != NULL) &&
(RtlEqualUnicodeString(&DomainName, &Transport->PrimaryDomain->PagedTransportName->Name->Name, TRUE)))) {
IsPrimaryDomain = TRUE;
BrowserServerList = PagedTransport->BrowserServerListBuffer;
BrowserServerListLength = PagedTransport->BrowserServerListLength;
}
if ((IsPrimaryDomain &&
(BrowserServerListLength == 0))
||
!IsPrimaryDomain
||
(InputBuffer->Parameters.GetBrowserServerList.ForceRescan)) {
//
// We need to re-gather the transport list.
// Re-acquire the BrowserServerList resource for exclusive access.
//
ExReleaseResource(&Transport->BrowserServerListResource);
TransportBrowserListAcquired = FALSE;
if (!ExAcquireResourceExclusive(&Transport->BrowserServerListResource, Wait)) {
try_return(Status = STATUS_PENDING);
}
TransportBrowserListAcquired = TRUE;
try {
//
// If we are being asked to rescan the list, free it up.
//
if (InputBuffer->Parameters.GetBrowserServerList.ForceRescan &&
PagedTransport->BrowserServerListBuffer != NULL) {
BowserFreeBrowserServerList(PagedTransport->BrowserServerListBuffer,
PagedTransport->BrowserServerListLength);
PagedTransport->BrowserServerListLength = 0;
PagedTransport->BrowserServerListBuffer = NULL;
}
} except (EXCEPTION_EXECUTE_HANDLER) {
try_return(Status = GetExceptionCode());
}
//
// If there are still no servers in the list, get the list.
//
Status = BowserGetBrowserServerList(Irp,
Transport,
(DomainName.Length == 0 ?
NULL :
&DomainName),
&BrowserServerList,
&BrowserServerListLength);
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
if (IsPrimaryDomain) {
//
// Save away the list of servers retreived in the transport.
//
PagedTransport->BrowserServerListBuffer = BrowserServerList;
PagedTransport->BrowserServerListLength = BrowserServerListLength;
}
}
//
// If there any servers in the browser server list, we want to
// pick the first 3 of them and return them to the caller.
//
if (BrowserServerListLength != 0) {
ULONG i;
try {
PWSTR *ServerList = OutputBuffer;
InputBuffer->Parameters.GetBrowserServerList.TotalEntries = 0;
InputBuffer->Parameters.GetBrowserServerList.EntriesRead = 0;
InputBuffer->Parameters.GetBrowserServerList.TotalBytesNeeded = 0;
//
// Now pick the first 3 entries from the list to return.
//
for ( i = 0 ; i < min(3, BrowserServerListLength) ; i ++ ) {
InputBuffer->Parameters.GetBrowserServerList.TotalEntries += 1;
InputBuffer->Parameters.GetBrowserServerList.TotalBytesNeeded += wcslen(BrowserServerList[i])*sizeof(WCHAR);
ServerList[i] = BrowserServerList[i];
dprintf(DPRT_CLIENT, ("Packing server name %ws into buffer...", ServerList[i]));
//
// Pack the entry into the users buffer.
//
if (BowserPackUnicodeString(&ServerList[i],
wcslen(ServerList[i])*sizeof(WCHAR),
OutputBufferDisplacement,
&ServerList[i+1],
&OutputBufferEnd)) {
dprintf(DPRT_CLIENT, ("...Successful.\n"));
InputBuffer->Parameters.GetBrowserServerList.EntriesRead += 1;
#if DBG
} else {
dprintf(DPRT_CLIENT, ("...Failed.\n"));
#endif
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
try_return(Status = GetExceptionCode());
}
}
//
// Set the number of bytes to copy on return.
//
*InputBufferLength = sizeof(LMDR_REQUEST_PACKET);
try_return(Status = STATUS_SUCCESS);
try_exit:NOTHING;
} finally {
if (Transport != NULL) {
if (TransportBrowserListAcquired) {
ExReleaseResource(&Transport->BrowserServerListResource);
}
BowserDereferenceTransport(Transport);
}
if (NT_SUCCESS(Status) && !IsPrimaryDomain) {
BowserFreeBrowserServerList(BrowserServerList,
BrowserServerListLength);
}
}
return(Status);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(InFsd);
}
NTSTATUS
HandleBecomeBackup (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine will queue a request that will complete when a request
to make the workstation become a backup browser is received.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
Status = BowserQueueNonBufferRequest(Irp,
&Transport->BecomeBackupQueue,
BowserCancelQueuedRequest
);
BowserDereferenceTransport(Transport);
return Status;
}
NTSTATUS
BecomeMaster (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine will queue a request that will complete when the workstation
becomes a master browser server.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
LOCK_TRANSPORT (Transport);
if (Transport->ElectionState == DeafToElections) {
Transport->ElectionState = Idle;
}
UNLOCK_TRANSPORT (Transport);
Status = BowserQueueNonBufferRequest(Irp,
&Transport->BecomeMasterQueue,
BowserCancelQueuedRequest
);
BowserDereferenceTransport(Transport);
return Status;
}
NTSTATUS
WaitForBrowserRequest (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine will queue a request that will complete when a client
workstation requests a backup list from a master browser server.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
#if 0
NTSTATUS Status;
PTRANSPORT Transport;
#endif
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
return STATUS_NOT_SUPPORTED;
#if 0
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
LOCK_TRANSPORT(Transport);
//
// See if we have a buffered GetBackupList request already waiting for
// the browser. If so, pull it off the queue and complete this request
// with the information from the queued packet.
//
if (!IsListEmpty(&Transport->QueuedGetBackupListRequests)) {
PLMDR_REQUEST_PACKET RequestPacket = Irp->AssociatedIrp.SystemBuffer;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PQUEUED_GET_BROWSER_REQUEST Request = NULL;
Request = (PQUEUED_GET_BROWSER_REQUEST)RemoveHeadList(&Transport->QueuedGetBackupListRequests);
Transport->NumberOfQueuedGetBackupListRequests -= 1;
UNLOCK_TRANSPORT(Transport);
if (Request->ClientNameLength+sizeof(WCHAR) > (USHORT)(IrpSp->Parameters.DeviceIoControl.OutputBufferLength-FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.WaitForBrowserServerRequest.Name))) {
Irp->IoStatus.Information = 0;
BowserStatistics.NumberOfMissedGetBrowserServerListRequests += 1;
BowserNumberOfMissedGetBrowserServerListRequests += 1;
Status = STATUS_BUFFER_TOO_SMALL;
} else {
RequestPacket->Parameters.WaitForBrowserServerRequest.Token = Request->Token;
RequestPacket->Parameters.WaitForBrowserServerRequest.RequestedCount = Request->RequestedCount;
//
// Time stamp this request.
//
RequestPacket->Parameters.WaitForBrowserServerRequest.TimeReceived = Request->TimeReceived;
#if DBG
RequestPacket->Parameters.WaitForBrowserServerRequest.TimeQueued = Request->TimeQueued;
RequestPacket->Parameters.WaitForBrowserServerRequest.TimeQueuedToBrowserThread = Request->TimeQueuedToBrowserThread;
#endif
RtlCopyMemory(RequestPacket->Parameters.WaitForBrowserServerRequest.Name, Request->ClientName, Request->ClientNameLength+sizeof(WCHAR));
RequestPacket->Parameters.WaitForBrowserServerRequest.Name[Request->ClientNameLength/sizeof(WCHAR)] = UNICODE_NULL;
RequestPacket->Parameters.WaitForBrowserServerRequest.RequestorNameLength = Request->ClientNameLength;
Irp->IoStatus.Information = FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.WaitForBrowserServerRequest.Name)+Request->ClientNameLength + sizeof(UNICODE_NULL);
Status = STATUS_SUCCESS;
}
FREE_POOL(Request);
BowserDereferenceTransport(Transport);
return Status;
}
Status = BowserQueueNonBufferRequest(Irp,
&Transport->WaitForBackupListQueue,
BowserCancelQueuedRequest
);
UNLOCK_TRANSPORT(Transport);
BowserDereferenceTransport(Transport);
return Status;
#endif
}
NTSTATUS
WaitForMasterAnnounce (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine will queue a request that will complete when the workstation
becomes a master browser server.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
Status = BowserQueueNonBufferRequest(Irp,
&Transport->WaitForMasterAnnounceQueue,
BowserCancelQueuedRequest
);
BowserDereferenceTransport(Transport);
return Status;
}
NTSTATUS
UpdateStatus(
IN PIRP Irp,
IN BOOLEAN InFsd,
IN PLMDR_REQUEST_PACKET InputBuffer
)
{
NTSTATUS Status = STATUS_SUCCESS;
PTRANSPORT Transport = NULL;
ULONG NewStatus;
BOOLEAN TransportLocked = FALSE;
BOOLEAN IsPrimaryDomainController;
PPAGED_TRANSPORT PagedTransport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Update status "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
if (InFsd) {
return (Status = STATUS_PENDING);
}
try {
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
return STATUS_INVALID_PARAMETER;
}
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
if ( Transport->PrimaryDomain == NULL ) {
BowserDereferenceTransport(Transport);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
PagedTransport = Transport->PagedTransport;
NewStatus = InputBuffer->Parameters.UpdateStatus.NewStatus;
BowserData.MaintainServerList = InputBuffer->Parameters.UpdateStatus.MaintainServerList;
BowserData.IsLanmanNt = InputBuffer->Parameters.UpdateStatus.IsLanmanNt;
IsPrimaryDomainController = InputBuffer->Parameters.UpdateStatus.IsPrimaryDomainController;
BowserData.IsDomainMaster = InputBuffer->Parameters.UpdateStatus.IsDomainMaster;
BowserData.IsDomainMember = InputBuffer->Parameters.UpdateStatus.IsMemberDomain;
} except (EXCEPTION_EXECUTE_HANDLER) {
if (Transport != NULL) {
BowserDereferenceTransport(Transport);
}
return GetExceptionCode();
}
BowserData.IsPrimaryDomainController = IsPrimaryDomainController;
LOCK_TRANSPORT(Transport);
TransportLocked = TRUE;
try {
PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
//
// We are being called to update our state. There are several
// actions that should be performed on the state change:
//
// New Role | Previous Role
// | Potential Browser | Backup Browser | Master Browser
// ----------+--------------------+----------------+----------------
// | | |
// Potential | N/A | N/A | N/A
// | | |
// ----------+--------------------+----------------+----------------
// | | |
// Backup | Update role | N/A | N/A
// | | |
// ----------+--------------------+----------------+----------------
// | | |
// Master | Update role | Update role | N/A
// | | |
// ----------+--------------------+----------------+----------------
// | | |
// None | Remove elect | Remove elect | Remove all names
// | | |
// ----------+--------------------+----------------+----------------
//
dprintf(DPRT_BROWSER, ("Update status to %lx\n", NewStatus));
PagedTransport->ServiceStatus = NewStatus;
//
// If we are a master, then update appropriately.
//
if (PagedTransport->Role == Master) {
try {
PagedTransport->NumberOfServersInTable = InputBuffer->Parameters.UpdateStatus.NumberOfServersInTable;
} except (EXCEPTION_EXECUTE_HANDLER) {
try_return(Status = GetExceptionCode());
}
//
// If the new status doesn't indicate that we should be a master
// browser, flag it as such.
//
if (!(NewStatus & SV_TYPE_MASTER_BROWSER)) {
dprintf(DPRT_BROWSER, ("New status indicates we are not a master browser\n"));
//
// We must be a backup now, if we're not a master.
//
PagedTransport->Role = Backup;
//
// Stop processing announcements on this transport.
//
Status = BowserForEachTransportName(Transport, BowserStopProcessingAnnouncements, NULL);
UNLOCK_TRANSPORT(Transport);
TransportLocked = FALSE;
Status = BowserDeleteTransportNameByName(Transport, &Transport->PrimaryDomain->PagedTransportName->Name->Name,
MasterBrowser);
if (!NT_SUCCESS(Status)) {
//
// BUGBUG: Log an error.
//
dprintf(DPRT_BROWSER, ("Unable to remove master name: %X\n", Status));
}
Status = BowserDeleteTransportNameByName(Transport, &Transport->PrimaryDomain->PagedTransportName->Name->Name,
DomainAnnouncement);
if (!NT_SUCCESS(Status)) {
//
// BUGBUG: Log an error.
//
dprintf(DPRT_BROWSER, ("Unable to domain announcement name: %X\n", Status));
}
if (!(NewStatus & SV_TYPE_BACKUP_BROWSER)) {
//
// We've stopped being a master browser, and we're not
// going to be a backup browser. We want to toss our
// cached browser server list just in case we're on the
// list.
//
ExAcquireResourceExclusive(&Transport->BrowserServerListResource, TRUE);
if (PagedTransport->BrowserServerListBuffer != NULL) {
BowserFreeBrowserServerList(PagedTransport->BrowserServerListBuffer,
PagedTransport->BrowserServerListLength);
PagedTransport->BrowserServerListLength = 0;
PagedTransport->BrowserServerListBuffer = NULL;
}
ExReleaseResource(&Transport->BrowserServerListResource);
}
LOCK_TRANSPORT(Transport);
TransportLocked = TRUE;
}
} else if (NewStatus & SV_TYPE_MASTER_BROWSER) {
dprintf(DPRT_BROWSER | DPRT_MASTER, ("New status indicates we should be master, but we're not.\n"));
UNLOCK_TRANSPORT(Transport);
TransportLocked = FALSE;
Status = BowserBecomeMaster (Transport);
LOCK_TRANSPORT(Transport);
dprintf(DPRT_BROWSER | DPRT_MASTER, ("Master promotion status: %lX.\n", Status));
TransportLocked = TRUE;
ASSERT ((PagedTransport->Role == Master) || !NT_SUCCESS(Status));
}
if (!NT_SUCCESS(Status) || PagedTransport->Role == Master) {
try_return(Status);
}
//
// If we are a backup, then update appropriately.
//
if (PagedTransport->Role == Backup) {
if (!(NewStatus & SV_TYPE_BACKUP_BROWSER)) {
dprintf(DPRT_BROWSER, ("New status indicates we are not a backup browser\n"));
PagedTransport->Role = PotentialBackup;
//
// We've stopped being a browser. We want to toss our cached
// browser list in case we're on the list.
//
ExAcquireResourceExclusive(&Transport->BrowserServerListResource, TRUE);
if (PagedTransport->BrowserServerListBuffer != NULL) {
BowserFreeBrowserServerList(PagedTransport->BrowserServerListBuffer,
PagedTransport->BrowserServerListLength);
PagedTransport->BrowserServerListLength = 0;
PagedTransport->BrowserServerListBuffer = NULL;
}
ExReleaseResource(&Transport->BrowserServerListResource);
}
} else if (NewStatus & SV_TYPE_BACKUP_BROWSER) {
dprintf(DPRT_BROWSER, ("New status indicates we are a backup, but we think we are not\n"));
PagedTransport->Role = Backup;
Status = STATUS_SUCCESS;
}
if (!NT_SUCCESS(Status) || PagedTransport->Role == Backup) {
try_return(Status);
}
//
// If we are a potential backup, then update appropriately.
//
if (PagedTransport->Role == PotentialBackup) {
if (!(NewStatus & SV_TYPE_POTENTIAL_BROWSER)) {
dprintf(DPRT_BROWSER, ("New status indicates we are not a potential browser\n"));
UNLOCK_TRANSPORT(Transport);
TransportLocked = FALSE;
Status = BowserDeleteTransportNameByName(Transport, &Transport->PrimaryDomain->PagedTransportName->Name->Name,
BrowserElection);
if (!NT_SUCCESS(Status)) {
//
// BUGBUG: Log an error.
//
dprintf(DPRT_BROWSER, ("Unable to remove election name: %X\n", Status));
try_return(Status);
}
LOCK_TRANSPORT(Transport);
TransportLocked = TRUE;
PagedTransport->Role = None;
}
} else if (NewStatus & SV_TYPE_POTENTIAL_BROWSER) {
dprintf(DPRT_BROWSER, ("New status indicates we are a potential browser, but we're not\n"));
PagedTransport->Role = PotentialBackup;
UNLOCK_TRANSPORT(Transport);
TransportLocked = FALSE;
Status = BowserAllocateName(&Transport->PrimaryDomain->PagedTransportName->Name->Name,
BrowserElection,
Transport);
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
LOCK_TRANSPORT(Transport);
TransportLocked = TRUE;
}
try_return(Status);
try_exit:NOTHING;
} finally {
if (TransportLocked) {
UNLOCK_TRANSPORT(Transport);
}
if (Transport != NULL) {
BowserDereferenceTransport(Transport);
}
}
return Status;
}
NTSTATUS
BowserStopProcessingAnnouncements(
IN PTRANSPORT_NAME TransportName,
IN PVOID Context
)
{
PAGED_CODE();
ASSERT (TransportName->Signature == STRUCTURE_SIGNATURE_TRANSPORTNAME);
ASSERT (TransportName->NameType == TransportName->PagedTransportName->Name->NameType);
if ((TransportName->NameType == OtherDomain) ||
(TransportName->NameType == MasterBrowser) ||
(TransportName->NameType == PrimaryDomain) ||
(TransportName->NameType == BrowserElection) ||
(TransportName->NameType == DomainAnnouncement)) {
if (TransportName->ProcessHostAnnouncements) {
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
TransportName->ProcessHostAnnouncements = FALSE;
}
}
return(STATUS_SUCCESS);
UNREFERENCED_PARAMETER(Context);
}
NTSTATUS
WaitForBrowserRoleChange (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine will queue a request that will complete when a request
to make the workstation become a backup browser is received.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
Status = BowserQueueNonBufferRequest(Irp,
&Transport->ChangeRoleQueue,
BowserCancelQueuedRequest
);
BowserDereferenceTransport(Transport);
return Status;
}
NTSTATUS
WriteMailslot (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength
)
/*++
Routine Description:
This routine will announce the primary domain to the world
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport;
UNICODE_STRING DestinationName;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Announce Domain "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
try {
PCHAR MailslotName = NULL;
try {
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
try_return(Status = STATUS_OBJECT_NAME_NOT_FOUND);
}
DestinationName.Length = (USHORT)InputBuffer->Parameters.SendDatagram.NameLength;
DestinationName.MaximumLength = (USHORT)InputBuffer->Parameters.SendDatagram.NameLength;
DestinationName.Buffer = InputBuffer->Parameters.SendDatagram.Name;
if (InputBuffer->Parameters.SendDatagram.MailslotNameLength != 0) {
//
// The mailslot name had better fit within the buffer.
//
if (InputBuffer->Parameters.SendDatagram.MailslotNameLength > InputBufferLength) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
MailslotName = ((PCHAR)InputBuffer->Parameters.SendDatagram.Name)+
InputBuffer->Parameters.SendDatagram.NameLength;
//
// If the name doesn't match its input length, fail the request.
//
if (strlen(MailslotName) != InputBuffer->Parameters.SendDatagram.MailslotNameLength - 1) {
try_return(Status = STATUS_INVALID_PARAMETER);
}
} else {
MailslotName = MAILSLOT_BROWSER_NAME;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
#if DBG
DbgBreakPoint();
#endif
try_return(Status = GetExceptionCode());
}
Status = BowserSendSecondClassMailslot(Transport,
&DestinationName,
InputBuffer->Parameters.SendDatagram.DestinationNameType,
OutputBuffer,
OutputBufferLength,
TRUE,
MailslotName,
NULL);
try_exit:NOTHING;
} finally {
if (Transport != NULL) {
BowserDereferenceTransport(Transport);
}
}
return Status;
}
NTSTATUS
WaitForNewMaster (
IN PIRP Irp,
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine will queue a request that will complete when a new workstation
becomes the master browser server.
Arguments:
IN PIRP Irp - I/O request packet describing request.
Return Value:
Status of operation.
Please note that this IRP is cancelable.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport;
UNICODE_STRING ExistingMasterName;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Get Announce Request "));
ExAcquireResourceExclusive(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Bowser already started\n"));
ExReleaseResource(&BowserDataResource);
return STATUS_REDIRECTOR_NOT_STARTED;
}
ExReleaseResource(&BowserDataResource);
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
if (Transport->PagedTransport->Flags & DIRECT_HOST_IPX) {
BowserDereferenceTransport(Transport);
return STATUS_NOT_SUPPORTED;
}
if (Transport->PagedTransport->MasterName.Length != 0) {
UNICODE_STRING ExistingMasterNameCopy;
WCHAR MasterNameBuffer[CNLEN+1];
ExistingMasterName.Buffer = InputBuffer->Parameters.GetMasterName.Name;
ExistingMasterName.Length = (USHORT)InputBuffer->Parameters.GetMasterName.MasterNameLength;
ExistingMasterNameCopy.Buffer = MasterNameBuffer;
ExistingMasterNameCopy.MaximumLength = sizeof(MasterNameBuffer);
Status = RtlUpcaseUnicodeString(&ExistingMasterNameCopy, &ExistingMasterName, FALSE);
if (!NT_SUCCESS(Status)) {
BowserDereferenceTransport(Transport);
return Status;
}
//
// If the name the application passed in was not the same as the
// name we have stored locally, we complete the request immediately,
// since the name changed between when we last determined the name
// and now.
//
LOCK_TRANSPORT(Transport);
if (!RtlEqualUnicodeString(&ExistingMasterNameCopy, &Transport->PagedTransport->MasterName, FALSE)) {
RtlCopyUnicodeString(&ExistingMasterNameCopy, &Transport->PagedTransport->MasterName);
UNLOCK_TRANSPORT(Transport);
InputBuffer->Parameters.GetMasterName.Name[0] = L'\\';
InputBuffer->Parameters.GetMasterName.Name[1] = L'\\';
RtlCopyMemory(&InputBuffer->Parameters.GetMasterName.Name[2], ExistingMasterNameCopy.Buffer,
ExistingMasterNameCopy.Length);
InputBuffer->Parameters.GetMasterName.MasterNameLength = ExistingMasterNameCopy.Length+2*sizeof(WCHAR);
InputBuffer->Parameters.GetMasterName.Name[2+(ExistingMasterNameCopy.Length/sizeof(WCHAR))] = UNICODE_NULL;
Irp->IoStatus.Information = FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.GetMasterName.Name) +
ExistingMasterNameCopy.Length+3*sizeof(WCHAR);;
BowserDereferenceTransport(Transport);
return STATUS_SUCCESS;
} else {
UNLOCK_TRANSPORT(Transport);
}
}
Status = BowserQueueNonBufferRequest(Irp,
&Transport->WaitForNewMasterNameQueue,
BowserCancelQueuedRequest
);
BowserDereferenceTransport(Transport);
return Status;
}
NTSTATUS
QueryStatistics(
IN PIRP Irp,
OUT PBOWSER_STATISTICS OutputBuffer,
IN OUT PULONG OutputBufferLength
)
{
KIRQL OldIrql;
if (*OutputBufferLength != sizeof(BOWSER_STATISTICS)) {
*OutputBufferLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
DISCARDABLE_CODE( BowserDiscardableCodeSection );
ACQUIRE_SPIN_LOCK(&BowserStatisticsLock, &OldIrql);
RtlCopyMemory(OutputBuffer, &BowserStatistics, sizeof(BOWSER_STATISTICS));
RELEASE_SPIN_LOCK(&BowserStatisticsLock, OldIrql);
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
return STATUS_SUCCESS;
}
NTSTATUS
ResetStatistics(
VOID
)
{
KIRQL OldIrql;
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
DISCARDABLE_CODE( BowserDiscardableCodeSection );
ACQUIRE_SPIN_LOCK(&BowserStatisticsLock, &OldIrql);
RtlZeroMemory(&BowserStatistics, sizeof(BOWSER_STATISTICS));
KeQuerySystemTime(&BowserStatistics.StartTime);
RELEASE_SPIN_LOCK(&BowserStatisticsLock, OldIrql);
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
return STATUS_SUCCESS;
}
NTSTATUS
BowserIpAddressChanged(
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine is called whenever the IP address of a transport changes.
NetBt uses the IP address to associate it's transport endpoint with the
appropriate NDIS driver. As such,
Arguments:
InputBuffer - Buffer specifying the name of the transport whose address
has changed.
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
PTRANSPORT Transport = NULL;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: IP Address changed"));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (InputBuffer->TransportName.Length == 0) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
//
// Find the transport whose address has changed.
//
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto ReturnStatus;
}
//
// Update all our information from the provider.
//
Status = BowserUpdateProviderInformation( Transport->PagedTransport );
ReturnStatus:
if (Transport != NULL) {
BowserDereferenceTransport(Transport);
}
return Status;
}
NTSTATUS
EnableDisableTransport (
IN PLMDR_REQUEST_PACKET InputBuffer
)
/*++
Routine Description:
This routine Implements the IOCTL to enable or disable a transport.
Arguments:
InputBuffer - Buffer indicating whether we should enable or disable the
transport.
Return Value:
Status of operation.
--*/
{
NTSTATUS Status;
PTRANSPORT Transport = NULL;
PPAGED_TRANSPORT PagedTransport;
PAGED_CODE();
dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: Enable/Disable transport"));
ExAcquireResourceShared(&BowserDataResource, TRUE);
if (BowserData.Initialized != TRUE) {
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
ExReleaseResource(&BowserDataResource);
Status = STATUS_REDIRECTOR_NOT_STARTED;
goto ReturnStatus;
}
ExReleaseResource(&BowserDataResource);
//
// Check some fields in the input buffer.
//
if (InputBuffer->Version != LMDR_REQUEST_PACKET_VERSION) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
if (InputBuffer->TransportName.Length == 0) {
Status = STATUS_INVALID_PARAMETER;
goto ReturnStatus;
}
//
// Find the transport whose address has changed.
//
Transport = BowserFindTransport(&InputBuffer->TransportName);
if (Transport == NULL) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto ReturnStatus;
}
PagedTransport = Transport->PagedTransport;
//
// Set the disabled bit correctly.
//
InputBuffer->Parameters.EnableDisableTransport.PreviouslyEnabled =
!PagedTransport->DisabledTransport;
if ( InputBuffer->Parameters.EnableDisableTransport.EnableTransport ) {
PagedTransport->DisabledTransport = FALSE;
//
// If the transport was previously disabled and this is an NTAS server,
// force an election.
//
if ( (!InputBuffer->Parameters.EnableDisableTransport.PreviouslyEnabled) &&
BowserData.IsLanmanNt ) {
BowserStartElection( Transport );
}
} else {
PagedTransport->DisabledTransport = TRUE;
//
// If we're disabling a previously enabled transport,
// ensure we're not the master browser.
//
BowserLoseElection( Transport );
}
Status = STATUS_SUCCESS;
ReturnStatus:
if (Transport != NULL) {
BowserDereferenceTransport(Transport);
}
return Status;
}