1235 lines
30 KiB
C
1235 lines
30 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
rxdevice.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the support routines for the APIs that call
|
||
into the redirector or the datagram receiver.
|
||
|
||
Author:
|
||
|
||
Balan Sethu Raman -- Created from the workstation service code
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "align.h"
|
||
#include "rxdrt.h"
|
||
#include "rxdevice.h"
|
||
#include "rxconfig.h"
|
||
#include "malloc.h"
|
||
|
||
#define SERVICE_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
|
||
|
||
//
|
||
// Buffer allocation size for enumeration output buffer.
|
||
//
|
||
#define INITIAL_ALLOCATION_SIZE 4096 // First attempt size
|
||
#define FUDGE_FACTOR_SIZE 1024 // Second try TotalBytesNeeded
|
||
// plus this amount
|
||
|
||
//
|
||
// Handle to the Redirector FSD
|
||
//
|
||
HANDLE RxRedirDeviceHandle = NULL;
|
||
HANDLE RxRedirAsyncDeviceHandle = NULL;
|
||
|
||
BOOLEAN LoadedRdbssInsteadOfRdr = FALSE;
|
||
|
||
//
|
||
// Handle to the Datagram Receiver DD
|
||
//
|
||
HANDLE RxDgReceiverDeviceHandle = NULL;
|
||
HANDLE RxDgrecAsyncDeviceHandle = NULL;
|
||
|
||
|
||
NTSTATUS
|
||
RxDeviceControlGetInfo(
|
||
IN DDTYPE DeviceDriverType,
|
||
IN HANDLE FileHandle,
|
||
IN ULONG DeviceControlCode,
|
||
IN PVOID RequestPacket,
|
||
IN ULONG RequestPacketLength,
|
||
OUT PVOID *OutputBuffer,
|
||
IN ULONG PreferedMaximumLength,
|
||
IN ULONG BufferHintSize,
|
||
OUT PULONG Information
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function allocates the buffer and fill it with the information
|
||
that is retrieved from the redirector or datagram receiver.
|
||
|
||
Arguments:
|
||
|
||
DeviceDriverType - Supplies the value which indicates whether to call
|
||
the redirector or the datagram receiver.
|
||
|
||
FileHandle - Supplies a handle to the file or device of which to get
|
||
information about.
|
||
|
||
DeviceControlCode - Supplies the NtFsControlFile or NtIoDeviceControlFile
|
||
function control code.
|
||
|
||
RequestPacket - Supplies a pointer to the device request packet.
|
||
|
||
RrequestPacketLength - Supplies the length of the device request packet.
|
||
|
||
OutputBuffer - Returns a pointer to the buffer allocated by this routine
|
||
which contains the use information requested. This pointer is set to
|
||
NULL if return code is not Success.
|
||
|
||
PreferedMaximumLength - Supplies the number of bytes of information to
|
||
return in the buffer. If this value is MAXULONG, we will try to
|
||
return all available information if there is enough memory resource.
|
||
|
||
BufferHintSize - Supplies the hint size of the output buffer so that the
|
||
memory allocated for the initial buffer will most likely be large
|
||
enough to hold all requested data.
|
||
|
||
Information - Returns the information code from the NtFsControlFile or
|
||
NtIoDeviceControlFile call.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
DWORD OutputBufferLength;
|
||
DWORD TotalBytesNeeded = 1;
|
||
ULONG OriginalResumeKey;
|
||
|
||
|
||
//
|
||
// If PreferedMaximumLength is MAXULONG, then we are supposed to get all
|
||
// the information, regardless of size. Allocate the output buffer of a
|
||
// reasonable size and try to use it. If this fails, the Redirector FSD
|
||
// will say how much we need to allocate.
|
||
//
|
||
if (PreferedMaximumLength == MAXULONG) {
|
||
OutputBufferLength = (BufferHintSize) ?
|
||
BufferHintSize :
|
||
INITIAL_ALLOCATION_SIZE;
|
||
}
|
||
else {
|
||
OutputBufferLength = PreferedMaximumLength;
|
||
}
|
||
|
||
OutputBufferLength = ROUND_UP_COUNT(OutputBufferLength, ALIGN_WCHAR);
|
||
|
||
if ((*OutputBuffer = malloc(OutputBufferLength)) == NULL) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
|
||
|
||
if (DeviceDriverType == Redirector) {
|
||
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) RequestPacket;
|
||
|
||
OriginalResumeKey = Rrp->Parameters.Get.ResumeHandle;
|
||
|
||
//
|
||
// Make the request of the Redirector
|
||
//
|
||
|
||
status = RxRedirFsControl(
|
||
FileHandle,
|
||
DeviceControlCode,
|
||
Rrp,
|
||
RequestPacketLength,
|
||
*OutputBuffer,
|
||
OutputBufferLength,
|
||
Information
|
||
);
|
||
|
||
if (status == ERROR_MORE_DATA) {
|
||
TotalBytesNeeded = Rrp->Parameters.Get.TotalBytesNeeded;
|
||
|
||
}
|
||
|
||
}
|
||
else {
|
||
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) RequestPacket;
|
||
|
||
OriginalResumeKey = Drrp->Parameters.EnumerateNames.ResumeHandle;
|
||
|
||
//
|
||
// Make the request of the Datagram Receiver
|
||
//
|
||
status = RxDgReceiverIoControl(
|
||
FileHandle,
|
||
DeviceControlCode,
|
||
Drrp,
|
||
RequestPacketLength,
|
||
*OutputBuffer,
|
||
OutputBufferLength,
|
||
NULL
|
||
);
|
||
|
||
if (status == ERROR_MORE_DATA) {
|
||
TotalBytesNeeded = Drrp->Parameters.EnumerateNames.TotalBytesNeeded;
|
||
}
|
||
}
|
||
|
||
if ((TotalBytesNeeded > OutputBufferLength) &&
|
||
(PreferedMaximumLength == MAXULONG)) {
|
||
|
||
//
|
||
// Initial output buffer allocated was too small and we need to return
|
||
// all data. First free the output buffer before allocating the
|
||
// required size plus a fudge factor just in case the amount of data
|
||
// grew.
|
||
//
|
||
|
||
free(*OutputBuffer);
|
||
|
||
OutputBufferLength =
|
||
ROUND_UP_COUNT((TotalBytesNeeded + FUDGE_FACTOR_SIZE),
|
||
ALIGN_WCHAR);
|
||
|
||
if ((*OutputBuffer = malloc(OutputBufferLength)) == NULL) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
|
||
|
||
//
|
||
// Try again to get the information from the redirector or datagram
|
||
// receiver
|
||
//
|
||
if (DeviceDriverType == Redirector) {
|
||
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) RequestPacket;
|
||
|
||
Rrp->Parameters.Get.ResumeHandle = OriginalResumeKey;
|
||
|
||
//
|
||
// Make the request of the Redirector
|
||
//
|
||
status = RxRedirFsControl(
|
||
FileHandle,
|
||
DeviceControlCode,
|
||
Rrp,
|
||
RequestPacketLength,
|
||
*OutputBuffer,
|
||
OutputBufferLength,
|
||
Information
|
||
);
|
||
}
|
||
else {
|
||
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) RequestPacket;
|
||
|
||
Drrp->Parameters.EnumerateNames.ResumeHandle = OriginalResumeKey;
|
||
|
||
//
|
||
// Make the request of the Datagram Receiver
|
||
//
|
||
|
||
status = RxDgReceiverIoControl(
|
||
FileHandle,
|
||
DeviceControlCode,
|
||
Drrp,
|
||
RequestPacketLength,
|
||
*OutputBuffer,
|
||
OutputBufferLength,
|
||
NULL
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// If not successful in getting any data, or if the caller asked for
|
||
// all available data with PreferedMaximumLength == MAXULONG and
|
||
// our buffer overflowed, free the output buffer and set its pointer
|
||
// to NULL.
|
||
//
|
||
if ((status != STATUS_SUCCESS && status != ERROR_MORE_DATA) ||
|
||
(TotalBytesNeeded == 0) ||
|
||
(PreferedMaximumLength == MAXULONG && status == ERROR_MORE_DATA)) {
|
||
|
||
free(*OutputBuffer);
|
||
*OutputBuffer = NULL;
|
||
|
||
//
|
||
// PreferedMaximumLength == MAXULONG and buffer overflowed means
|
||
// we do not have enough memory to satisfy the request.
|
||
//
|
||
if (status == ERROR_MORE_DATA) {
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RxOpenRedirector(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens the NT LAN Man redirector FSD.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntstatus;
|
||
UNICODE_STRING DeviceName;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
|
||
//
|
||
// Open the redirector device.
|
||
//
|
||
RtlInitUnicodeString(&DeviceName,
|
||
DD_NFS2_DEVICE_NAME_U);
|
||
|
||
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
&DeviceName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
ntstatus = NtOpenFile(
|
||
&RxRedirDeviceHandle,
|
||
SYNCHRONIZE,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
FILE_SHARE_VALID_FLAGS,
|
||
FILE_SYNCHRONOUS_IO_NONALERT
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
RxRedirDeviceHandle = NULL;
|
||
return ntstatus;
|
||
}
|
||
|
||
ntstatus = NtOpenFile(
|
||
&RxRedirAsyncDeviceHandle,
|
||
FILE_READ_DATA | FILE_WRITE_DATA,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
FILE_SHARE_VALID_FLAGS,
|
||
0L
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
RxRedirAsyncDeviceHandle = NULL;
|
||
}
|
||
|
||
return ntstatus;
|
||
}
|
||
|
||
NTSTATUS
|
||
RxOpenDgReceiver(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens the NT LAN Man Datagram Receiver driver.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntstatus;
|
||
UNICODE_STRING DeviceName;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
|
||
//
|
||
// Open the redirector device.
|
||
//
|
||
|
||
RtlInitUnicodeString( &DeviceName, DD_BROWSER_DEVICE_NAME_U);
|
||
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
&DeviceName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
ntstatus = NtOpenFile(
|
||
&RxDgReceiverDeviceHandle,
|
||
SYNCHRONIZE,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
FILE_SHARE_VALID_FLAGS,
|
||
FILE_SYNCHRONOUS_IO_NONALERT
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
RxDgReceiverDeviceHandle = NULL;
|
||
return ntstatus;
|
||
}
|
||
|
||
ntstatus = NtOpenFile(
|
||
&RxDgrecAsyncDeviceHandle,
|
||
FILE_READ_DATA | FILE_WRITE_DATA,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
FILE_SHARE_VALID_FLAGS,
|
||
0L
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
RxDgrecAsyncDeviceHandle = NULL;
|
||
}
|
||
|
||
return ntstatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RxUnloadDriver(
|
||
IN LPWSTR DriverNameString
|
||
)
|
||
{
|
||
ULONG Privileges[1];
|
||
LPWSTR DriverRegistryName;
|
||
UNICODE_STRING DriverRegistryString;
|
||
NTSTATUS Status;
|
||
NTSTATUS ntstatus;
|
||
|
||
|
||
DriverRegistryName = (LPWSTR) malloc(
|
||
(UINT) (sizeof(SERVICE_REGISTRY_KEY) +
|
||
(wcslen(DriverNameString) *
|
||
sizeof(WCHAR)))
|
||
);
|
||
|
||
if (DriverRegistryName == NULL) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
|
||
Privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
||
|
||
Status = RxGetPrivilege(1, Privileges);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
free(DriverRegistryName);
|
||
return Status;
|
||
}
|
||
|
||
wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
|
||
wcscat(DriverRegistryName, DriverNameString);
|
||
|
||
RtlInitUnicodeString(&DriverRegistryString, DriverRegistryName);
|
||
|
||
ntstatus = NtUnloadDriver(&DriverRegistryString);
|
||
|
||
free(DriverRegistryName);
|
||
|
||
RxReleasePrivilege();
|
||
|
||
return ntstatus;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RxLoadDriver(
|
||
IN LPWSTR DriverNameString
|
||
)
|
||
{
|
||
ULONG Privileges[1];
|
||
LPWSTR DriverRegistryName;
|
||
UNICODE_STRING DriverRegistryString;
|
||
NTSTATUS Status;
|
||
NTSTATUS ntstatus;
|
||
|
||
|
||
|
||
DriverRegistryName = (LPWSTR) malloc(
|
||
(UINT) (sizeof(SERVICE_REGISTRY_KEY) +
|
||
(wcslen(DriverNameString) *
|
||
sizeof(WCHAR)))
|
||
);
|
||
|
||
if (DriverRegistryName == NULL) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
Privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
||
|
||
Status = RxGetPrivilege(1, Privileges);
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
free(DriverRegistryName);
|
||
return Status;
|
||
}
|
||
|
||
wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
|
||
wcscat(DriverRegistryName, DriverNameString);
|
||
|
||
RtlInitUnicodeString(&DriverRegistryString, DriverRegistryName);
|
||
|
||
ntstatus = NtLoadDriver(&DriverRegistryString);
|
||
|
||
RxReleasePrivilege();
|
||
|
||
free(DriverRegistryName);
|
||
|
||
if (ntstatus != STATUS_SUCCESS && ntstatus != STATUS_IMAGE_ALREADY_LOADED) {
|
||
|
||
LPWSTR subString[1];
|
||
|
||
|
||
subString[0] = DriverNameString;
|
||
}
|
||
|
||
return ntstatus;
|
||
}
|
||
|
||
NTSTATUS
|
||
RxStopRedirector(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine close the LAN Man Redirector device.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
LMR_REQUEST_PACKET Rrp;
|
||
LMDR_REQUEST_PACKET Drp;
|
||
NTSTATUS Status;
|
||
|
||
Rrp.Version = REQUEST_PACKET_VERSION;
|
||
|
||
Status = RxRedirFsControl(
|
||
RxRedirDeviceHandle,
|
||
FSCTL_LMR_STOP,
|
||
&Rrp,
|
||
sizeof(LMR_REQUEST_PACKET),
|
||
NULL,
|
||
0,
|
||
NULL);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
RxStopDgReceiver(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stops the datagram receiver.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
if (RxDgReceiverDeviceHandle != NULL) {
|
||
LMDR_REQUEST_PACKET Drp;
|
||
|
||
Drp.Version = LMDR_REQUEST_PACKET_VERSION;
|
||
|
||
(void) RxDgReceiverIoControl(
|
||
RxDgReceiverDeviceHandle,
|
||
IOCTL_LMDR_STOP,
|
||
&Drp,
|
||
sizeof(LMDR_REQUEST_PACKET),
|
||
NULL,
|
||
0,
|
||
NULL
|
||
);
|
||
} else {
|
||
DbgPrint("[RxDevice] Invalid datagram receiver handle\n");
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RxRedirFsControl(
|
||
IN HANDLE FileHandle,
|
||
IN ULONG RedirControlCode,
|
||
IN PLMR_REQUEST_PACKET Rrp,
|
||
IN ULONG RrpLength,
|
||
IN PVOID SecondBuffer OPTIONAL,
|
||
IN ULONG SecondBufferLength,
|
||
OUT PULONG Information OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
FileHandle - Supplies a handle to the file or device on which the service
|
||
is being performed.
|
||
|
||
RedirControlCode - Supplies the NtFsControlFile function code given to
|
||
the redirector.
|
||
|
||
Rrp - Supplies the redirector request packet.
|
||
|
||
RrpLength - Supplies the length of the redirector request packet.
|
||
|
||
SecondBuffer - Supplies the second buffer in call to NtFsControlFile.
|
||
|
||
SecondBufferLength - Supplies the length of the second buffer.
|
||
|
||
Information - Returns the information field of the I/O status block.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS ntstatus;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
//
|
||
// Send the request to the Redirector FSD.
|
||
//
|
||
ntstatus = NtFsControlFile(
|
||
FileHandle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
RedirControlCode,
|
||
Rrp,
|
||
RrpLength,
|
||
SecondBuffer,
|
||
SecondBufferLength
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(Information)) {
|
||
*Information = IoStatusBlock.Information;
|
||
}
|
||
|
||
return ntstatus;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
RxDgReceiverIoControl(
|
||
IN HANDLE FileHandle,
|
||
IN ULONG DgReceiverControlCode,
|
||
IN PLMDR_REQUEST_PACKET Drp,
|
||
IN ULONG DrpSize,
|
||
IN PVOID SecondBuffer OPTIONAL,
|
||
IN ULONG SecondBufferLength,
|
||
OUT PULONG Information OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
FileHandle - Supplies a handle to the file or device on which the service
|
||
is being performed.
|
||
|
||
DgReceiverControlCode - Supplies the NtDeviceIoControlFile function code
|
||
given to the datagram receiver.
|
||
|
||
Drp - Supplies the datagram receiver request packet.
|
||
|
||
DrpSize - Supplies the length of the datagram receiver request packet.
|
||
|
||
SecondBuffer - Supplies the second buffer in call to NtDeviceIoControlFile.
|
||
|
||
SecondBufferLength - Supplies the length of the second buffer.
|
||
|
||
Information - Returns the information field of the I/O status block.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS ntstatus;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
|
||
if (FileHandle == NULL) {
|
||
return STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
Drp->TransportName.Length = 0;
|
||
|
||
//
|
||
// Send the request to the Datagram Receiver DD.
|
||
//
|
||
ntstatus = NtDeviceIoControlFile(
|
||
FileHandle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
DgReceiverControlCode,
|
||
Drp,
|
||
DrpSize,
|
||
SecondBuffer,
|
||
SecondBufferLength
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(Information)) {
|
||
*Information = IoStatusBlock.Information;
|
||
}
|
||
|
||
return ntstatus;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
RxAsyncBindTransport(
|
||
IN LPWSTR transportName,
|
||
IN DWORD qualityOfService,
|
||
IN PLIST_ENTRY pHeader
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function async binds the specified transport to the redirector
|
||
and the datagram receiver.
|
||
|
||
NOTE: The transport name length pass to the redirector and
|
||
datagram receiver is the number of bytes.
|
||
|
||
Arguments:
|
||
|
||
transportName - Supplies the name of the transport to bind to.
|
||
|
||
qualityOfService - Supplies a value which specifies the search
|
||
order of the transport with respect to other transports. The
|
||
highest value is searched first.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntstatus;
|
||
NTSTATUS status;
|
||
DWORD size;
|
||
DWORD redirSize;
|
||
DWORD dgrecSize;
|
||
DWORD nameLength;
|
||
PRX_BIND pBind;
|
||
PRX_BIND_REDIR pBindRedir;
|
||
PRX_BIND_DGREC pBindDgrec;
|
||
|
||
nameLength = wcslen( transportName);
|
||
|
||
//
|
||
// Make sure *Size-s are DWORD aligned.
|
||
//
|
||
|
||
dgrecSize = redirSize = size = (nameLength & 1) ? sizeof( WCHAR) : 0;
|
||
|
||
//
|
||
// Then add the fixed part to *Size-s.
|
||
//
|
||
|
||
size += sizeof( RX_BIND) + nameLength * sizeof( WCHAR);
|
||
redirSize += sizeof( RX_BIND_REDIR) + nameLength * sizeof( WCHAR);
|
||
dgrecSize += sizeof( RX_BIND_DGREC) +
|
||
nameLength * sizeof( WCHAR)
|
||
;
|
||
|
||
|
||
pBind = (PVOID) malloc(
|
||
(UINT) (size + redirSize + dgrecSize)
|
||
);
|
||
|
||
if ( pBind == NULL) {
|
||
return GetLastError();
|
||
}
|
||
|
||
pBind->TransportNameLength = nameLength * sizeof( WCHAR);
|
||
wcscpy( pBind->TransportName, transportName);
|
||
pBind->Redir = pBindRedir = (PRX_BIND_REDIR)( (PCHAR)pBind + size);
|
||
pBind->Dgrec = pBindDgrec = (PRX_BIND_DGREC)( (PCHAR)pBindRedir + redirSize);
|
||
|
||
pBindRedir->EventHandle = INVALID_HANDLE_VALUE;
|
||
pBindRedir->Bound = FALSE;
|
||
pBindRedir->Packet.Version = REQUEST_PACKET_VERSION;
|
||
pBindRedir->Packet.Parameters.Bind.QualityOfService = qualityOfService;
|
||
pBindRedir->Packet.Parameters.Bind.TransportNameLength =
|
||
nameLength * sizeof( WCHAR);
|
||
wcscpy( pBindRedir->Packet.Parameters.Bind.TransportName, transportName);
|
||
|
||
pBindDgrec->EventHandle = INVALID_HANDLE_VALUE;
|
||
pBindDgrec->Bound = FALSE;
|
||
pBindDgrec->Packet.Version = LMDR_REQUEST_PACKET_VERSION;
|
||
pBindDgrec->Packet.Level = 0; // Indicate computername doesn't follow transport name
|
||
pBindDgrec->Packet.Parameters.Bind.TransportNameLength =
|
||
nameLength * sizeof( WCHAR);
|
||
wcscpy( pBindDgrec->Packet.Parameters.Bind.TransportName, transportName);
|
||
|
||
pBindRedir->EventHandle = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
if ( pBindRedir->EventHandle == INVALID_HANDLE_VALUE) {
|
||
status = GetLastError();
|
||
goto tail_exit;
|
||
}
|
||
|
||
ntstatus = NtFsControlFile(
|
||
RxRedirAsyncDeviceHandle,
|
||
pBindRedir->EventHandle,
|
||
NULL, // apc routine
|
||
NULL, // apc context
|
||
&pBindRedir->IoStatusBlock,
|
||
FSCTL_LMR_BIND_TO_TRANSPORT, // control code
|
||
&pBindRedir->Packet,
|
||
sizeof( LMR_REQUEST_PACKET) +
|
||
pBindRedir->Packet.Parameters.Bind.TransportNameLength,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
if ( ntstatus != STATUS_PENDING) {
|
||
CloseHandle( pBindRedir->EventHandle);
|
||
pBindRedir->EventHandle = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
|
||
pBindDgrec->EventHandle = CreateEvent(
|
||
NULL,
|
||
TRUE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
if ( pBindDgrec->EventHandle == INVALID_HANDLE_VALUE) {
|
||
status = GetLastError();
|
||
goto tail_exit;
|
||
}
|
||
|
||
ntstatus = NtDeviceIoControlFile(
|
||
RxDgrecAsyncDeviceHandle,
|
||
pBindDgrec->EventHandle,
|
||
NULL,
|
||
NULL,
|
||
&pBindDgrec->IoStatusBlock,
|
||
IOCTL_LMDR_BIND_TO_TRANSPORT,
|
||
&pBindDgrec->Packet,
|
||
dgrecSize,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
if ( ntstatus != STATUS_PENDING) {
|
||
CloseHandle( pBindDgrec->EventHandle);
|
||
pBindDgrec->EventHandle = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
tail_exit:
|
||
InsertTailList( pHeader, &pBind->ListEntry);
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
RxBindTransport(
|
||
IN LPTSTR TransportName,
|
||
IN DWORD QualityOfService,
|
||
OUT LPDWORD ErrorParameter OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function binds the specified transport to the redirector
|
||
and the datagram receiver.
|
||
|
||
NOTE: The transport name length pass to the redirector and
|
||
datagram receiver is the number of bytes.
|
||
|
||
Arguments:
|
||
|
||
TransportName - Supplies the name of the transport to bind to.
|
||
|
||
QualityOfService - Supplies a value which specifies the search
|
||
order of the transport with respect to other transports. The
|
||
highest value is searched first.
|
||
|
||
ErrorParameter - Returns the identifier to the invalid parameter if
|
||
this function returns ERROR_INVALID_PARAMETER.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
DWORD RequestPacketSize;
|
||
DWORD TransportNameSize = wcslen(TransportName) * sizeof(TCHAR);
|
||
|
||
PLMR_REQUEST_PACKET Rrp;
|
||
PLMDR_REQUEST_PACKET Drrp;
|
||
|
||
//
|
||
// Size of request packet buffer
|
||
//
|
||
RequestPacketSize = wcslen(TransportName) * sizeof(WCHAR) +
|
||
max(sizeof(LMR_REQUEST_PACKET),
|
||
sizeof(LMDR_REQUEST_PACKET));
|
||
|
||
//
|
||
// Allocate memory for redirector/datagram receiver request packet
|
||
//
|
||
if ((Rrp = (PVOID) malloc((UINT) RequestPacketSize)) == NULL) {
|
||
return GetLastError();
|
||
}
|
||
|
||
//
|
||
// Get redirector to bind to transport
|
||
//
|
||
Rrp->Version = REQUEST_PACKET_VERSION;
|
||
Rrp->Parameters.Bind.QualityOfService = QualityOfService;
|
||
|
||
Rrp->Parameters.Bind.TransportNameLength = TransportNameSize;
|
||
wcscpy(Rrp->Parameters.Bind.TransportName, TransportName);
|
||
|
||
if ((status = RxRedirFsControl(
|
||
RxRedirDeviceHandle,
|
||
FSCTL_LMR_BIND_TO_TRANSPORT,
|
||
Rrp,
|
||
sizeof(LMR_REQUEST_PACKET) +
|
||
Rrp->Parameters.Bind.TransportNameLength,
|
||
//Rrp, BUGBUG: rdr bugchecks!
|
||
//RequestPacketSize, specify NULL for now
|
||
NULL,
|
||
0,
|
||
NULL
|
||
)) != STATUS_SUCCESS) {
|
||
|
||
if (status == ERROR_INVALID_PARAMETER &&
|
||
ARGUMENT_PRESENT(ErrorParameter)) {
|
||
|
||
*ErrorParameter = Rrp->Parameters.Bind.WkstaParameter;
|
||
}
|
||
|
||
(void) free(Rrp);
|
||
return status;
|
||
}
|
||
|
||
|
||
//
|
||
// Get dgrec to bind to transport
|
||
//
|
||
|
||
//
|
||
// Make use of the same request packet buffer as FSCtl to
|
||
// redirector.
|
||
//
|
||
Drrp = (PLMDR_REQUEST_PACKET) Rrp;
|
||
|
||
Drrp->Version = LMDR_REQUEST_PACKET_VERSION;
|
||
|
||
Drrp->Parameters.Bind.TransportNameLength = TransportNameSize;
|
||
wcscpy(Drrp->Parameters.Bind.TransportName, TransportName);
|
||
|
||
status = RxDgReceiverIoControl(
|
||
RxDgReceiverDeviceHandle,
|
||
IOCTL_LMDR_BIND_TO_TRANSPORT,
|
||
Drrp,
|
||
RequestPacketSize,
|
||
NULL,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
(void) free(Rrp);
|
||
return status;
|
||
}
|
||
|
||
|
||
VOID
|
||
RxUnbindTransport2(
|
||
IN PRX_BIND pBind
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function unbinds the specified transport from the redirector
|
||
and the datagram receiver.
|
||
|
||
Arguments:
|
||
|
||
pBind - structure constructed via RxAsyncBindTransport()
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
// NTSTATUS status;
|
||
PRX_BIND_REDIR pBindRedir = pBind->Redir;
|
||
PRX_BIND_DGREC pBindDgrec = pBind->Dgrec;
|
||
|
||
|
||
//
|
||
// Get redirector to unbind from transport
|
||
//
|
||
|
||
if ( pBindRedir->Bound == TRUE) {
|
||
pBindRedir->Packet.Parameters.Unbind.TransportNameLength
|
||
= pBind->TransportNameLength;
|
||
memcpy(
|
||
pBindRedir->Packet.Parameters.Unbind.TransportName,
|
||
pBind->TransportName,
|
||
pBind->TransportNameLength
|
||
);
|
||
|
||
(VOID)NtFsControlFile(
|
||
RxRedirDeviceHandle,
|
||
NULL,
|
||
NULL, // apc routine
|
||
NULL, // apc context
|
||
&pBindRedir->IoStatusBlock,
|
||
FSCTL_LMR_UNBIND_FROM_TRANSPORT, // control code
|
||
&pBindRedir->Packet,
|
||
sizeof( LMR_REQUEST_PACKET) +
|
||
pBindRedir->Packet.Parameters.Unbind.TransportNameLength,
|
||
NULL,
|
||
0
|
||
);
|
||
pBindRedir->Bound = FALSE;
|
||
}
|
||
|
||
//
|
||
// Get datagram receiver to unbind from transport
|
||
//
|
||
|
||
if ( pBindDgrec->Bound == TRUE) {
|
||
|
||
pBindDgrec->Packet.Parameters.Unbind.TransportNameLength
|
||
= pBind->TransportNameLength;
|
||
memcpy(
|
||
pBindDgrec->Packet.Parameters.Unbind.TransportName,
|
||
pBind->TransportName,
|
||
pBind->TransportNameLength
|
||
);
|
||
|
||
(VOID)NtDeviceIoControlFile(
|
||
RxDgReceiverDeviceHandle,
|
||
NULL,
|
||
NULL, // apc routine
|
||
NULL, // apc context
|
||
&pBindDgrec->IoStatusBlock,
|
||
FSCTL_LMR_UNBIND_FROM_TRANSPORT, // control code
|
||
&pBindDgrec->Packet,
|
||
sizeof( LMR_REQUEST_PACKET) +
|
||
pBindDgrec->Packet.Parameters.Unbind.TransportNameLength,
|
||
NULL,
|
||
0
|
||
);
|
||
pBindDgrec->Bound = FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RxUnbindTransport(
|
||
IN LPTSTR TransportName,
|
||
IN DWORD ForceLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function unbinds the specified transport from the redirector
|
||
and the datagram receiver.
|
||
|
||
NOTE: The transport name length pass to the redirector and
|
||
datagram receiver is the number of bytes.
|
||
|
||
Arguments:
|
||
|
||
TransportName - Supplies the name of the transport to bind to.
|
||
|
||
ForceLevel - Supplies the force level to delete active connections
|
||
on the specified transport.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
DWORD RequestPacketSize;
|
||
DWORD TransportNameSize = wcslen(TransportName) * sizeof(TCHAR);
|
||
|
||
PLMR_REQUEST_PACKET Rrp;
|
||
PLMDR_REQUEST_PACKET Drrp;
|
||
|
||
//
|
||
// Size of request packet buffer
|
||
//
|
||
RequestPacketSize = wcslen(TransportName) * sizeof(WCHAR) +
|
||
max(sizeof(LMR_REQUEST_PACKET),
|
||
sizeof(LMDR_REQUEST_PACKET));
|
||
|
||
//
|
||
// Allocate memory for redirector/datagram receiver request packet
|
||
//
|
||
if ((Rrp = (PVOID) malloc((UINT) RequestPacketSize)) == NULL) {
|
||
return GetLastError();
|
||
}
|
||
|
||
|
||
//
|
||
// Get redirector to unbind from transport
|
||
//
|
||
Rrp->Version = REQUEST_PACKET_VERSION;
|
||
Rrp->Level = ForceLevel;
|
||
|
||
Rrp->Parameters.Unbind.TransportNameLength = TransportNameSize;
|
||
wcscpy(Rrp->Parameters.Unbind.TransportName, TransportName);
|
||
|
||
if ((status = RxRedirFsControl(
|
||
RxRedirDeviceHandle,
|
||
FSCTL_LMR_UNBIND_FROM_TRANSPORT,
|
||
Rrp,
|
||
sizeof(LMR_REQUEST_PACKET) +
|
||
Rrp->Parameters.Unbind.TransportNameLength,
|
||
NULL,
|
||
0,
|
||
NULL
|
||
)) != STATUS_SUCCESS) {
|
||
(void) free(Rrp);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Get datagram receiver to unbind from transport
|
||
//
|
||
|
||
//
|
||
// Make use of the same request packet buffer as FSCtl to
|
||
// redirector.
|
||
//
|
||
Drrp = (PLMDR_REQUEST_PACKET) Rrp;
|
||
|
||
Drrp->Version = LMDR_REQUEST_PACKET_VERSION;
|
||
Drrp->Level = ForceLevel;
|
||
|
||
Drrp->Parameters.Unbind.TransportNameLength = TransportNameSize;
|
||
wcscpy(Drrp->Parameters.Unbind.TransportName, TransportName);
|
||
|
||
if ((status = RxDgReceiverIoControl(
|
||
RxDgReceiverDeviceHandle,
|
||
IOCTL_LMDR_UNBIND_FROM_TRANSPORT,
|
||
Drrp,
|
||
RequestPacketSize,
|
||
NULL,
|
||
0,
|
||
NULL
|
||
)) != STATUS_SUCCESS) {
|
||
|
||
// BUGBUG: This is a hack until the bowser supports XNS and LOOP.
|
||
|
||
if (status == STATUS_NOT_FOUND) {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
(void) free(Rrp);
|
||
return status;
|
||
}
|
||
|
||
|
||
|