You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1029 lines
27 KiB
1029 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Driver.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the DRIVER_INITIALIZATION routine for the
|
|
SMB Transport and other routines that are specific to the NT implementation
|
|
of a driver.
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "ip2netbios.h"
|
|
|
|
#include "driver2.tmh"
|
|
|
|
BOOL
|
|
IsNetBTSmbEnabled(
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
NotifyNetBT(
|
|
IN DWORD dwNetBTAction
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, SmbDriverEntry)
|
|
#pragma alloc_text(INIT, IsNetBTSmbEnabled)
|
|
#pragma alloc_text(PAGE, NotifyNetBT)
|
|
#pragma alloc_text(PAGE, SmbDispatchCleanup)
|
|
#pragma alloc_text(PAGE, SmbDispatchClose)
|
|
#pragma alloc_text(PAGE, SmbDispatchCreate)
|
|
#pragma alloc_text(PAGE, SmbDispatchDevCtrl)
|
|
#pragma alloc_text(PAGE, SmbDispatchPnP)
|
|
#pragma alloc_text(PAGE, SmbUnload)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
NotifyNetBT(
|
|
IN DWORD dwNetBTAction
|
|
)
|
|
{
|
|
UNICODE_STRING uncWinsDeviceName = { 0 };
|
|
PFILE_OBJECT pWinsFileObject = NULL;
|
|
PDEVICE_OBJECT pWinsDeviceObject = NULL;
|
|
PIRP pIrp = NULL;
|
|
IO_STATUS_BLOCK IoStatusBlock = { 0 };
|
|
KEVENT Event = { 0 };
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
//
|
|
// Notify NetBT to destroy its NetbiosSmb
|
|
//
|
|
RtlInitUnicodeString(&uncWinsDeviceName, L"\\Device\\NetBt_Wins_Export");
|
|
status = IoGetDeviceObjectPointer(
|
|
&uncWinsDeviceName,
|
|
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
|
|
&pWinsFileObject,
|
|
&pWinsDeviceObject
|
|
);
|
|
if (STATUS_SUCCESS != status) {
|
|
goto error;
|
|
}
|
|
pIrp = IoBuildDeviceIoControlRequest (
|
|
IOCTL_NETBT_ENABLE_DISABLE_NETBIOS_SMB,
|
|
pWinsDeviceObject,
|
|
&dwNetBTAction,
|
|
sizeof(dwNetBTAction),
|
|
NULL,
|
|
0,
|
|
FALSE,
|
|
&Event,
|
|
&IoStatusBlock
|
|
);
|
|
if (NULL == pIrp) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto error;
|
|
}
|
|
|
|
status = IoCallDriver(pWinsDeviceObject, pIrp);
|
|
if (STATUS_PENDING == status) {
|
|
ASSERT (0);
|
|
KeWaitForSingleObject(
|
|
&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
status = IoStatusBlock.Status;
|
|
}
|
|
|
|
error:
|
|
if (pWinsFileObject != NULL) {
|
|
ObDereferenceObject(pWinsFileObject);
|
|
pWinsFileObject = NULL;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL
|
|
IsNetBTSmbEnabled(
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES ObAttr = { 0 };
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hRootKey = NULL;
|
|
HANDLE hKey = NULL;
|
|
UNICODE_STRING uncParams = { 0 };
|
|
BOOL fUseSmbFromNetBT = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Construct the registry path for the HKLM\System\CCS\Services
|
|
//
|
|
uncParams = RegistryPath[0];
|
|
while(uncParams.Length > 0 && uncParams.Buffer[uncParams.Length/sizeof(WCHAR) - 1] != L'\\') {
|
|
uncParams.Length -= sizeof(WCHAR);
|
|
}
|
|
uncParams.Length -= sizeof(WCHAR);
|
|
|
|
InitializeObjectAttributes (
|
|
&ObAttr,
|
|
&uncParams,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
status = ZwOpenKey (&hRootKey, KEY_READ | KEY_WRITE, &ObAttr);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
RtlInitUnicodeString(&uncParams, L"NetBT");
|
|
InitializeObjectAttributes (
|
|
&ObAttr,
|
|
&uncParams,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
hRootKey,
|
|
NULL
|
|
);
|
|
status = ZwOpenKey(&hKey, KEY_READ | KEY_WRITE, &ObAttr);
|
|
ZwClose(hRootKey);
|
|
hRootKey = hKey;
|
|
hKey = NULL;
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
fUseSmbFromNetBT = TRUE;
|
|
//
|
|
// From now on, an error means NetBT's Smb enabled
|
|
//
|
|
RtlInitUnicodeString(&uncParams, L"Parameters");
|
|
InitializeObjectAttributes (
|
|
&ObAttr,
|
|
&uncParams,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
hRootKey,
|
|
NULL
|
|
);
|
|
status = ZwOpenKey (&hKey, KEY_READ | KEY_WRITE, &ObAttr);
|
|
ZwClose(hRootKey);
|
|
hRootKey = hKey;
|
|
hKey = NULL;
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
fUseSmbFromNetBT = !(SmbReadULong(hRootKey, L"UseNewSmb", 0, 0));
|
|
if (fUseSmbFromNetBT) {
|
|
goto cleanup;
|
|
}
|
|
|
|
status = NotifyNetBT(NETBT_DISABLE_NETBIOS_SMB);
|
|
status = STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
if (hRootKey != NULL) {
|
|
ZwClose(hRootKey);
|
|
}
|
|
if (hKey != NULL) {
|
|
ZwClose(hKey);
|
|
}
|
|
return fUseSmbFromNetBT;
|
|
}
|
|
|
|
static KTIMER DelayedInitTimer;
|
|
static KDPC DelayedInitDpc;
|
|
static WORK_QUEUE_ITEM DelayedInitWorkItem;
|
|
|
|
static VOID
|
|
SmbDelayedInitRtn(
|
|
PVOID pvUnused1
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
status = SmbInitTdi();
|
|
ObDereferenceObject(&(SmbCfg.SmbDeviceObject->DeviceObject));
|
|
}
|
|
|
|
static VOID
|
|
SmbDelayedInitTimeoutRtn(
|
|
IN PKDPC Dpc,
|
|
IN PVOID Ctx,
|
|
IN PVOID SystemArg1,
|
|
IN PVOID SystemArg2
|
|
)
|
|
{
|
|
ExInitializeWorkItem(&DelayedInitWorkItem, SmbDelayedInitRtn, NULL);
|
|
ExQueueWorkItem(&DelayedInitWorkItem, DelayedWorkQueue);
|
|
}
|
|
|
|
static NTSTATUS
|
|
SmbDelayedInitTdi(
|
|
DWORD dwDelayedTime
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
LARGE_INTEGER DueTime = { 0 };
|
|
|
|
KeInitializeTimer(&DelayedInitTimer);
|
|
KeInitializeDpc(&DelayedInitDpc, SmbDelayedInitTimeoutRtn, NULL);
|
|
DueTime.QuadPart = UInt32x32To64(dwDelayedTime,(LONG)10000);
|
|
DueTime.QuadPart = -DueTime.QuadPart;
|
|
ObReferenceObject(&(SmbCfg.SmbDeviceObject->DeviceObject));
|
|
KeSetTimer(&DelayedInitTimer, DueTime, &DelayedInitDpc);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN OUT PDEVICE_OBJECT *SmbDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialization routine for the SMB device driver.
|
|
This routine creates the device object for the SMB
|
|
device and calls a routine to perform other driver initialization.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by the system.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The function value is the final status from the initialization
|
|
operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlZeroMemory(&SmbCfg, sizeof(SmbCfg));
|
|
if (SmbDevice) {
|
|
*SmbDevice = NULL;
|
|
}
|
|
|
|
SmbCfg.DriverObject = DriverObject;
|
|
InitializeListHead(&SmbCfg.IPDeviceList);
|
|
InitializeListHead(&SmbCfg.PendingDeleteIPDeviceList);
|
|
KeInitializeSpinLock(&SmbCfg.UsedIrpsLock);
|
|
InitializeListHead(&SmbCfg.UsedIrps);
|
|
KeInitializeSpinLock(&SmbCfg.Lock);
|
|
|
|
SmbCfg.FspProcess =(PEPROCESS)PsGetCurrentProcess();
|
|
|
|
status = ExInitializeResourceLite(&SmbCfg.Resource);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
status = SmbInitRegistry(RegistryPath);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
#if DBG
|
|
if (SmbReadULong(SmbCfg.ParametersKey, L"Break", 0, 0)) {
|
|
DbgBreakPoint();
|
|
}
|
|
SmbCfg.DebugFlag = SmbReadULong(SmbCfg.ParametersKey, L"DebugFlag", 0, 0);
|
|
#endif
|
|
|
|
#ifdef STANDALONE_SMB
|
|
if (IsNetBTSmbEnabled(RegistryPath)) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Abort the initialization of SMB since NetBT's Smb device is enabled\n"));
|
|
SmbTrace(SMB_TRACE_PNP, ("Abort the initialization of SMB since NetBT's Smb device is enabled"));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
#endif
|
|
|
|
SmbCfg.EnableNagling = SmbReadULong (
|
|
SmbCfg.ParametersKey,
|
|
SMB_REG_ENABLE_NAGLING,
|
|
0, // Disabled by default
|
|
0
|
|
);
|
|
SmbCfg.DnsTimeout = SmbReadULong (
|
|
SmbCfg.ParametersKey,
|
|
SMB_REG_DNS_TIME_OUT,
|
|
SMB_REG_DNS_TIME_OUT_DEFAULT,
|
|
SMB_REG_DNS_TIME_OUT_MIN
|
|
);
|
|
SmbCfg.DnsMaxResolver = SmbReadLong (
|
|
SmbCfg.ParametersKey,
|
|
SMB_REG_DNS_MAX_RESOLVER,
|
|
SMB_REG_DNS_RESOLVER_DEFAULT,
|
|
SMB_REG_DNS_RESOLVER_MIN
|
|
);
|
|
if (SmbCfg.DnsMaxResolver > DNS_MAX_RESOLVER) {
|
|
SmbCfg.DnsMaxResolver = DNS_MAX_RESOLVER;
|
|
}
|
|
|
|
SmbCfg.uIPv6Protection = SmbReadULong(
|
|
SmbCfg.ParametersKey,
|
|
SMB_REG_IPV6_PROTECTION,
|
|
SMB_REG_IPV6_PROTECTION_DEFAULT,
|
|
0
|
|
);
|
|
|
|
SmbCfg.bIPv6EnableOutboundGlobal = SmbReadULong(
|
|
SmbCfg.ParametersKey,
|
|
SMB_REG_IPV6_ENABLE_OUTBOUND_GLOBAL,
|
|
FALSE, // default value
|
|
0
|
|
);
|
|
|
|
#ifndef NO_LOOKASIDE_LIST
|
|
//
|
|
// Initialize Lookaside Lists
|
|
//
|
|
ExInitializeNPagedLookasideList(
|
|
&SmbCfg.ConnectObjectPool,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
sizeof(SMB_CONNECT),
|
|
CONNECT_OBJECT_POOL_TAG,
|
|
0
|
|
);
|
|
SmbCfg.ConnectObjectPoolInitialized = TRUE;
|
|
ExInitializeNPagedLookasideList(
|
|
&SmbCfg.TcpContextPool,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
sizeof(SMB_TCP_CONTEXT),
|
|
TCP_CONTEXT_POOL_TAG,
|
|
0
|
|
);
|
|
SmbCfg.TcpContextPoolInitialized = TRUE;
|
|
#endif
|
|
|
|
#ifdef STANDALONE_SMB
|
|
TdiInitialize();
|
|
#endif
|
|
|
|
status = SmbCreateSmbDevice(&SmbCfg.SmbDeviceObject, SMB_TCP_PORT, SMB_ENDPOINT_NAME);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
status = SmbInitDnsResolver();
|
|
BAIL_OUT_ON_ERROR(status);
|
|
status = SmbInitIPv6NetbiosMappingTable();
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
#ifdef STANDALONE_SMB
|
|
status = SmbDelayedInitTdi(1000);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
#endif
|
|
|
|
if (SmbDevice) {
|
|
*SmbDevice = &(SmbCfg.SmbDeviceObject->DeviceObject);
|
|
}
|
|
return (status);
|
|
|
|
cleanup:
|
|
SmbUnload(DriverObject);
|
|
return status;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
SmbDispatchCleanup(
|
|
IN PSMB_DEVICE Device,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the SMB driver's dispatch function for IRP_MJ_CLEANUP
|
|
requests.
|
|
|
|
This function is called when the last reference to the handle is closed.
|
|
Hence, an NtClose() results in an IRP_MJ_CLEANUP first, and then an
|
|
IRP_MJ_CLOSE. This function runs down all activity on the object, and
|
|
when the close comes in the object is actually deleted.
|
|
|
|
Arguments:
|
|
|
|
device - ptr to device object for target device
|
|
pIrp - ptr to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SmbCfg.Unloading) {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IrpSp->MajorFunction == IRP_MJ_CLEANUP);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return(status);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
SmbDispatchClose(
|
|
IN PSMB_DEVICE Device,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the SMB driver's dispatch function for IRP_MJ_CLOSE
|
|
requests. This is called after Cleanup (above) is called.
|
|
|
|
Arguments:
|
|
|
|
device - ptr to device object for target device
|
|
pIrp - ptr to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
an NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SmbCfg.Unloading) {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto cleanup;
|
|
}
|
|
ASSERT(Device == SmbCfg.SmbDeviceObject);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IrpSp->MajorFunction == IRP_MJ_CLOSE);
|
|
|
|
switch(PtrToUlong(IrpSp->FileObject->FsContext2)) {
|
|
case SMB_TDI_CONTROL:
|
|
status = SmbCloseControl(Device, Irp);
|
|
break;
|
|
|
|
case SMB_TDI_CLIENT:
|
|
status = SmbCloseClient(Device, Irp);
|
|
break;
|
|
|
|
case SMB_TDI_CONNECT:
|
|
status = SmbCloseConnection(Device, Irp);
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ASSERT(status != STATUS_PENDING);
|
|
|
|
cleanup:
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
PFILE_FULL_EA_INFORMATION
|
|
SmbFindInEA(
|
|
IN PFILE_FULL_EA_INFORMATION eabuf,
|
|
IN PCHAR wanted
|
|
);
|
|
#pragma alloc_text(PAGE, SmbFindInEA)
|
|
|
|
PFILE_FULL_EA_INFORMATION
|
|
SmbFindInEA(
|
|
IN PFILE_FULL_EA_INFORMATION eabuf,
|
|
IN PCHAR wanted
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function check for the "Wanted" string in the Ea structure and
|
|
returns a pointer to the extended attribute structure
|
|
representing the given extended attribute name.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
pointer to the extended attribute structure, or NULL if not found.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
while(1) {
|
|
if (strncmp(eabuf->EaName, wanted, eabuf->EaNameLength) == 0) {
|
|
return eabuf;
|
|
}
|
|
|
|
if (0 == eabuf->NextEntryOffset) {
|
|
return NULL;
|
|
}
|
|
eabuf = (PFILE_FULL_EA_INFORMATION) ((PUCHAR)eabuf + eabuf->NextEntryOffset);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmbDispatchCreate(
|
|
IN PSMB_DEVICE Device,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the SMB driver's dispatch function for IRP_MJ_CREATE
|
|
requests. It is called as a consequence of one of the following:
|
|
|
|
a. TdiOpenConnection("\Device\Smb_Elnkii0"),
|
|
b. TdiOpenAddress("\Device\Smb_Elnkii0"),
|
|
|
|
Arguments:
|
|
|
|
Device - ptr to device object being opened
|
|
pIrp - ptr to I/O request packet
|
|
pIrp->Status => return status
|
|
pIrp->MajorFunction => IRP_MD_CREATE
|
|
pIrp->MinorFunction => not used
|
|
pIrp->FileObject => ptr to file obj created by I/O system. SMB fills in FsContext
|
|
pIrp->AssociatedIrp.SystemBuffer => ptr to EA buffer with address of obj to open(Netbios Name)
|
|
pIrp->Parameters.Create.EaLength => length of buffer specifying the Xport Addr.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or STATUS_PENDING
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PFILE_FULL_EA_INFORMATION ea, wanted_ea;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SmbCfg.Unloading) {
|
|
SmbPrint(SMB_TRACE_PNP, ("DispatchCreate: Smb is unloading\n"));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto cleanup;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(Device == SmbCfg.SmbDeviceObject);
|
|
ASSERT(IrpSp->MajorFunction == IRP_MJ_CREATE);
|
|
|
|
ea = Irp->AssociatedIrp.SystemBuffer;
|
|
if (NULL == ea || KernelMode != Irp->RequestorMode) {
|
|
status = SmbCreateControl(Device, Irp);
|
|
} else if (NULL != (wanted_ea = SmbFindInEA(ea, TdiConnectionContext))) {
|
|
// Not allow to pass in both a connection request and a transport address request
|
|
ASSERT(!SmbFindInEA(ea, TdiTransportAddress));
|
|
status = SmbCreateConnection(Device, Irp, wanted_ea);
|
|
} else if (NULL != (wanted_ea = SmbFindInEA(ea, TdiTransportAddress))) {
|
|
// Not allow to pass in both a connection request and a transport address request
|
|
ASSERT(!SmbFindInEA(ea, TdiConnectionContext));
|
|
status = SmbCreateClient(Device, Irp, wanted_ea);
|
|
} else {
|
|
status = STATUS_INVALID_EA_NAME;
|
|
}
|
|
|
|
cleanup:
|
|
ASSERT(status != STATUS_PENDING);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return(status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDispatchDevCtrl(
|
|
IN PSMB_DEVICE Device,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the SMB driver's dispatch function for all
|
|
IRP_MJ_DEVICE_CONTROL requests.
|
|
|
|
Arguments:
|
|
|
|
device - ptr to device object for target device
|
|
pIrp - ptr to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
if (SmbCfg.Unloading) {
|
|
SmbPrint(SMB_TRACE_PNP, ("DispatchDevCtrl: Smb is unloading\n"));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto cleanup;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
switch(IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_SMB_START:
|
|
SmbTrace(SMB_TRACE_IOCTL, ("IOCTL_SMB_START"));
|
|
SmbPrint(SMB_TRACE_IOCTL, ("IOCTL_SMB_START\n"));
|
|
status = SmbTdiRegister(Device);
|
|
break;
|
|
|
|
case IOCTL_SMB_STOP:
|
|
SmbTrace(SMB_TRACE_IOCTL, ("IOCTL_SMB_STOP"));
|
|
SmbPrint(SMB_TRACE_IOCTL, ("IOCTL_SMB_STOP\n"));
|
|
status = SmbTdiDeregister(Device);
|
|
break;
|
|
|
|
case IOCTL_SMB_DNS:
|
|
status = SmbNewResolver(Device, Irp);
|
|
break;
|
|
|
|
case IOCTL_SMB_ENABLE_NAGLING:
|
|
SmbTrace(SMB_TRACE_IOCTL, ("IOCTL_SMB_ENABLE_NAGLING"));
|
|
SmbPrint(SMB_TRACE_IOCTL, ("IOCTL_SMB_ENABLE_NAGLING\n"));
|
|
SmbCfg.EnableNagling = TRUE;
|
|
status = STATUS_SUCCESS;
|
|
TODO("Turn on nagling for each connection in the pool");
|
|
break;
|
|
|
|
case IOCTL_SMB_DISABLE_NAGLING:
|
|
SmbTrace(SMB_TRACE_IOCTL, ("IOCTL_SMB_DISABLE_NAGLING"));
|
|
SmbPrint(SMB_TRACE_IOCTL, ("IOCTL_SMB_DISABLE_NAGLING\n"));
|
|
SmbCfg.EnableNagling = FALSE;
|
|
status = STATUS_SUCCESS;
|
|
TODO("Turn off nagling for each connection in the pool");
|
|
break;
|
|
|
|
case IOCTL_SMB_SET_IPV6_PROTECTION_LEVEL:
|
|
//
|
|
// Set IPv6 Protection level
|
|
//
|
|
status = IoctlSetIPv6Protection(Device, Irp, IrpSp);
|
|
break;
|
|
|
|
case IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER:
|
|
SmbTrace(SMB_TRACE_IOCTL, ("IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER"));
|
|
SmbPrint(SMB_TRACE_IOCTL, ("IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER\n"));
|
|
if (Irp->RequestorMode != KernelMode) {
|
|
//
|
|
// There is no point for usermode application to query FastSend
|
|
//
|
|
status = STATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
(PVOID)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer) = (PVOID)SmbSend;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
//
|
|
// Legacy NetBT stuff
|
|
// The following Ioctl is used by the Rdr/Srv to add/remove addresses from the SmbDevice
|
|
//
|
|
case IOCTL_NETBT_SET_SMBDEVICE_BIND_INFO:
|
|
status = SmbSetBindingInfo(Device, Irp);
|
|
break;
|
|
|
|
//
|
|
// Used by Srv service
|
|
//
|
|
case IOCTL_NETBT_SET_TCP_CONNECTION_INFO:
|
|
status = SmbClientSetTcpInfo(Device, Irp);
|
|
break;
|
|
|
|
//
|
|
// Who is going to use this?
|
|
//
|
|
case IOCTL_NETBT_GET_CONNECTIONS:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
cleanup:
|
|
if (status != STATUS_PENDING) {
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDispatchInternalCtrl(
|
|
IN PSMB_DEVICE Device,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the driver's dispatch function for all
|
|
IRP_MJ_INTERNAL_DEVICE_CONTROL requests.
|
|
|
|
Arguments:
|
|
|
|
device - ptr to device object for target device
|
|
pIrp - ptr to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
BOOL bShouldCompleteIrp = TRUE;
|
|
|
|
if (SmbCfg.Unloading) {
|
|
SmbPrint(SMB_TRACE_PNP, ("DispatchIntDevCtrl: Smb is unloading\n"));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto cleanup;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch(IrpSp->MinorFunction) {
|
|
case TDI_ACCEPT:
|
|
status = SmbAccept(Device, Irp);
|
|
break;
|
|
case TDI_LISTEN:
|
|
status = SmbListen(Device, Irp);
|
|
break;
|
|
case TDI_ASSOCIATE_ADDRESS:
|
|
status = SmbAssociateAddress(Device, Irp);
|
|
break;
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
status = SmbDisAssociateAddress(Device, Irp);
|
|
break;
|
|
case TDI_CONNECT:
|
|
status = SmbConnect(Device, Irp);
|
|
break;
|
|
case TDI_DISCONNECT:
|
|
status = SmbDisconnect(Device, Irp);
|
|
break;
|
|
case TDI_SEND:
|
|
status = SmbSend(Device, Irp);
|
|
break;
|
|
case TDI_RECEIVE:
|
|
status = SmbReceive(Device, Irp);
|
|
break;
|
|
case TDI_SEND_DATAGRAM:
|
|
status = SmbSendDatagram(Device, Irp);
|
|
break;
|
|
case TDI_RECEIVE_DATAGRAM:
|
|
status = SmbReceiveDatagram(Device, Irp);
|
|
break;
|
|
case TDI_QUERY_INFORMATION:
|
|
status = SmbQueryInformation(Device, Irp, &bShouldCompleteIrp);
|
|
break;
|
|
case TDI_SET_EVENT_HANDLER:
|
|
status = SmbSetEventHandler(Device, Irp);
|
|
break;
|
|
case TDI_SET_INFORMATION:
|
|
status = SmbSetInformation(Device, Irp);
|
|
break;
|
|
|
|
#if DBG
|
|
//
|
|
// 0x7f is a request by the Redir to put a "magic bullet" out
|
|
// on the wire, to trigger the Network General Sniffer.
|
|
//
|
|
case 0x7f:
|
|
#endif
|
|
default:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
cleanup:
|
|
if (status != STATUS_PENDING && bShouldCompleteIrp) {
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
} else {
|
|
//
|
|
// Don't mark IRP pending here because it could have been completed.
|
|
//
|
|
}
|
|
return(status);
|
|
} // SmbDispatchInternalCtrl
|
|
|
|
|
|
NTSTATUS
|
|
SmbQueryTargetDeviceRelationForConnection(
|
|
PSMB_CONNECT ConnectObject,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PFILE_OBJECT TcpFileObject = NULL;
|
|
PDEVICE_OBJECT TcpDeviceObject = NULL;
|
|
PIO_STACK_LOCATION IrpSp = NULL, IrpSpNext = NULL;
|
|
KIRQL Irql;
|
|
NTSTATUS status = STATUS_CONNECTION_INVALID;
|
|
|
|
SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
|
|
if (NULL == ConnectObject->TcpContext) {
|
|
TcpFileObject = NULL;
|
|
} else {
|
|
TcpFileObject = ConnectObject->TcpContext->Connect.ConnectObject;
|
|
ASSERT(TcpFileObject != NULL);
|
|
|
|
TcpDeviceObject = IoGetRelatedDeviceObject (TcpFileObject);
|
|
if (NULL == TcpDeviceObject) {
|
|
TcpFileObject = NULL;
|
|
} else {
|
|
ObReferenceObject(TcpFileObject);
|
|
}
|
|
}
|
|
SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_TDI);
|
|
|
|
if (NULL == TcpFileObject) {
|
|
status = STATUS_CONNECTION_INVALID;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Simply pass the Irp on by to the Transport, and let it
|
|
// fill in the info
|
|
//
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
IrpSpNext = IoGetNextIrpStackLocation (Irp);
|
|
*IrpSpNext = *IrpSp;
|
|
|
|
IoSetCompletionRoutine (Irp, NULL, NULL, FALSE, FALSE, FALSE);
|
|
IrpSpNext->FileObject = TcpFileObject;
|
|
IrpSpNext->DeviceObject = TcpDeviceObject;
|
|
|
|
status = IoCallDriver(TcpDeviceObject, Irp);
|
|
ObDereferenceObject(TcpFileObject);
|
|
|
|
//
|
|
// Irp could be completed. Don't access it anymore
|
|
//
|
|
|
|
return status;
|
|
|
|
cleanup:
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDispatchPnP(
|
|
IN PSMB_DEVICE Device,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
PSMB_CLIENT_ELEMENT ClientObject = NULL;
|
|
PSMB_CONNECT ConnectObject = NULL;
|
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (IrpSp->MinorFunction) {
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
if (IrpSp->Parameters.QueryDeviceRelations.Type==TargetDeviceRelation) {
|
|
|
|
ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_TDI);
|
|
ClientObject = SmbVerifyAndReferenceClient(IrpSp->FileObject, SMB_REF_TDI);
|
|
|
|
if (ConnectObject != NULL) {
|
|
|
|
ASSERT(ClientObject == NULL);
|
|
return SmbQueryTargetDeviceRelationForConnection(ConnectObject, Irp);
|
|
|
|
} else if (ClientObject != NULL) {
|
|
|
|
SmbDereferenceClient(ClientObject, SMB_REF_TDI);
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
|
|
ASSERT (0);
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
SmbUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the SMB driver's dispatch function for Unload requests
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by the system.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
SmbCfg.Unloading = TRUE;
|
|
|
|
if (NULL == SmbCfg.DriverObject) {
|
|
return;
|
|
}
|
|
|
|
#ifdef STANDALONE_SMB
|
|
SmbShutdownTdi();
|
|
#endif
|
|
|
|
SmbShutdownRegistry();
|
|
|
|
SmbShutdownDnsResolver();
|
|
SmbShutdownIPv6NetbiosMappingTable();
|
|
|
|
SmbDestroySmbDevice(SmbCfg.SmbDeviceObject);
|
|
SmbCfg.SmbDeviceObject = NULL;
|
|
|
|
#ifndef NO_LOOKASIDE_LIST
|
|
if (SmbCfg.ConnectObjectPoolInitialized) {
|
|
ExDeleteNPagedLookasideList(&SmbCfg.ConnectObjectPool);
|
|
SmbCfg.ConnectObjectPoolInitialized = FALSE;
|
|
}
|
|
if (SmbCfg.TcpContextPoolInitialized) {
|
|
ExDeleteNPagedLookasideList(&SmbCfg.TcpContextPool);
|
|
SmbCfg.TcpContextPoolInitialized = FALSE;
|
|
}
|
|
#endif
|
|
|
|
SmbCfg.DriverObject = NULL;
|
|
ExDeleteResourceLite(&SmbCfg.Resource);
|
|
NotifyNetBT(NETBT_RESTORE_NETBIOS_SMB);
|
|
}
|