3221 lines
83 KiB
C
3221 lines
83 KiB
C
/*++
|
||
|
||
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;
|
||
|
||
}
|