1755 lines
52 KiB
C
1755 lines
52 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Driver.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the DRIVER_INITIALIZATION routine for the
|
||
NBT Transport and other routines that are specific to the NT implementation
|
||
of a driver.
|
||
|
||
Author:
|
||
|
||
Jim Stewart (Jimst) 10-2-92
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "precomp.h"
|
||
#include <nbtioctl.h>
|
||
|
||
#include "driver.tmh"
|
||
|
||
#if DBG
|
||
// allocate storage for the global debug flag NbtDebug
|
||
//ULONG NbtDebug = NBT_DEBUG_KDPRINTS| NBT_DEBUG_NETBIOS_EX;
|
||
ULONG NbtDebug = 0;
|
||
#endif // DBG
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtDispatchCleanup(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtDispatchClose(
|
||
IN PDEVICE_OBJECT device,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtDispatchCreate(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtDispatchDevCtrl(
|
||
IN PDEVICE_OBJECT device,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtDispatchInternalCtrl(
|
||
IN PDEVICE_OBJECT device,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
#ifdef _PNP_POWER_
|
||
VOID
|
||
NbtUnload(
|
||
IN PDRIVER_OBJECT device
|
||
);
|
||
#endif // _PNP_POWER_
|
||
|
||
NTSTATUS
|
||
NbtDispatchPnP(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
PFILE_FULL_EA_INFORMATION
|
||
FindInEA(
|
||
IN PFILE_FULL_EA_INFORMATION start,
|
||
IN PCHAR wanted
|
||
);
|
||
|
||
VOID
|
||
ReturnIrp(
|
||
IN PIRP pIrp,
|
||
IN int status
|
||
);
|
||
|
||
VOID
|
||
MakePending(
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtCreateAdminSecurityDescriptor(
|
||
IN PDEVICE_OBJECT dev
|
||
);
|
||
|
||
#ifdef _PNP_POWER_DBG_
|
||
//
|
||
//Debug Stuff for DbgBreakPoint -- REMOVE
|
||
//
|
||
NTSTATUS
|
||
NbtOpenRegistry(
|
||
IN HANDLE NbConfigHandle,
|
||
IN PWSTR String,
|
||
OUT PHANDLE pHandle
|
||
);
|
||
#endif // _PNP_POWER_DBG_
|
||
|
||
#ifdef _PNP_POWER_
|
||
HANDLE TdiClientHandle = NULL;
|
||
HANDLE TdiProviderHandle = NULL;
|
||
extern tTIMERQ TimerQ;
|
||
#endif // _PNP_POWER_
|
||
|
||
#ifdef _NETBIOSLESS
|
||
tDEVICECONTEXT *pNbtSmbDevice = NULL;
|
||
#endif // _NETBIOSLESS
|
||
|
||
//******************* Pageable Routine Declarations ****************
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma CTEMakePageable(INIT, DriverEntry)
|
||
#pragma CTEMakePageable(PAGE, NbtDispatchCleanup)
|
||
#pragma CTEMakePageable(PAGE, NbtDispatchClose)
|
||
#pragma CTEMakePageable(PAGE, NbtDispatchCreate)
|
||
#pragma CTEMakePageable(PAGE, NbtDispatchDevCtrl)
|
||
#pragma CTEMakePageable(PAGE, FindInEA)
|
||
#pragma CTEMakePageable(PAGE, NbtUnload)
|
||
#endif
|
||
//******************* Pageable Routine Declarations ****************
|
||
|
||
//----------------------------------------------------------------------------
|
||
VOID
|
||
CleanupDriverEntry(
|
||
ULONG CleanupStage
|
||
)
|
||
{
|
||
PSINGLE_LIST_ENTRY pSingleListEntry;
|
||
PMDL pMdl;
|
||
PVOID pBuffer;
|
||
LIST_ENTRY *pListEntry;
|
||
tDGRAM_SEND_TRACKING *pTracker;
|
||
|
||
switch (CleanupStage)
|
||
{
|
||
case (6):
|
||
NbtDestroyDevice (pWinsDeviceContext, FALSE);
|
||
|
||
#ifdef RASAUTODIAL
|
||
//
|
||
// Unbind fron the RAS driver if we were bound
|
||
//
|
||
NbtAcdUnbind ();
|
||
#endif // RASAUTODIAL
|
||
|
||
// Fall through
|
||
|
||
case (5):
|
||
if (pNbtSmbDevice)
|
||
{
|
||
NbtDestroyDevice (pNbtSmbDevice, FALSE);
|
||
pNbtSmbDevice = NULL;
|
||
}
|
||
|
||
if (NbtConfig.OutOfRsrc.pDpc)
|
||
{
|
||
CTEMemFree (NbtConfig.OutOfRsrc.pDpc);
|
||
}
|
||
if (NbtConfig.OutOfRsrc.pIrp)
|
||
{
|
||
IoFreeIrp (NbtConfig.OutOfRsrc.pIrp);
|
||
}
|
||
|
||
// Fall through
|
||
|
||
case (4):
|
||
while (NbtConfig.SessionMdlFreeSingleList.Next)
|
||
{
|
||
pSingleListEntry = PopEntryList(&NbtConfig.SessionMdlFreeSingleList);
|
||
pMdl = CONTAINING_RECORD(pSingleListEntry,MDL,Next);
|
||
pBuffer = MmGetMdlVirtualAddress (pMdl);
|
||
CTEMemFree (pBuffer);
|
||
IoFreeMdl (pMdl);
|
||
}
|
||
|
||
while (NbtConfig.DgramMdlFreeSingleList.Next)
|
||
{
|
||
pSingleListEntry = PopEntryList(&NbtConfig.DgramMdlFreeSingleList);
|
||
pMdl = CONTAINING_RECORD(pSingleListEntry,MDL,Next);
|
||
pBuffer = MmGetMdlVirtualAddress (pMdl);
|
||
CTEMemFree (pBuffer);
|
||
IoFreeMdl (pMdl);
|
||
}
|
||
|
||
// Fall through
|
||
|
||
case (3):
|
||
//
|
||
// InitNotOs has been called
|
||
//
|
||
|
||
DestroyTimerQ();
|
||
|
||
while (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ))
|
||
{
|
||
pListEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ);
|
||
pTracker = CONTAINING_RECORD(pListEntry,tDGRAM_SEND_TRACKING,Linkage);
|
||
CTEMemFree (pTracker);
|
||
}
|
||
|
||
DestroyHashTables ();
|
||
ExDeleteResourceLite (&NbtConfig.Resource); // Delete the resource
|
||
|
||
// Fall through
|
||
|
||
case (2):
|
||
//
|
||
// Read registry has been called!
|
||
//
|
||
CTEMemFree (NbtConfig.pLmHosts);
|
||
CTEMemFree (NbtConfig.pScope);
|
||
if (NbtConfig.pTcpBindName)
|
||
{
|
||
CTEMemFree (NbtConfig.pTcpBindName);
|
||
}
|
||
|
||
// Fall through
|
||
|
||
case (1):
|
||
CTEMemFree (NbtConfig.pRegistry.Buffer);
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the initialization routine for the NBT device driver.
|
||
This routine creates the device object for the NBT
|
||
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;
|
||
tDEVICES *pBindDevices=NULL;
|
||
tDEVICES *pExportDevices=NULL;
|
||
tADDRARRAY *pAddrArray=NULL;
|
||
PMDL pMdl;
|
||
PSINGLE_LIST_ENTRY pSingleListEntry;
|
||
|
||
UNICODE_STRING ucWinsDeviceBindName;
|
||
UNICODE_STRING ucWinsDeviceExportName;
|
||
UNICODE_STRING ucSmbDeviceBindName;
|
||
UNICODE_STRING ucSmbDeviceExportName;
|
||
UNICODE_STRING ucNetBTClientName;
|
||
UNICODE_STRING ucNetBTProviderName;
|
||
|
||
TDI_CLIENT_INTERFACE_INFO TdiClientInterface;
|
||
|
||
#ifdef _PNP_POWER_DBG_
|
||
//
|
||
//Debug Stuff for DbgBreakPoint
|
||
//
|
||
OBJECT_ATTRIBUTES TmpObjectAttributes;
|
||
HANDLE NbtConfigHandle;
|
||
ULONG Disposition;
|
||
PWSTR ParametersString = L"Parameters";
|
||
HANDLE ParametersHandle;
|
||
#endif // _PNP_POWER_DBG_
|
||
|
||
CTEPagedCode();
|
||
|
||
#ifdef _NBT_WMI_SOFTWARE_TRACING_
|
||
WPP_INIT_TRACING(DriverObject, RegistryPath);
|
||
#endif
|
||
|
||
#ifdef _PNP_POWER_DBG_
|
||
InitializeObjectAttributes (&TmpObjectAttributes,
|
||
RegistryPath, // name
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
|
||
NULL, // root
|
||
NULL); // security descriptor
|
||
|
||
status = ZwCreateKey (&NbtConfigHandle,
|
||
KEY_READ,
|
||
&TmpObjectAttributes,
|
||
0, // title index
|
||
NULL, // class
|
||
0, // create options
|
||
&Disposition); // disposition
|
||
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
NbtLogEvent (EVENT_NBT_CREATE_DRIVER, status, 0x109);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
status = NbtOpenRegistry (NbtConfigHandle, ParametersString, &ParametersHandle);
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
ZwClose(NbtConfigHandle);
|
||
return (status);
|
||
}
|
||
|
||
if (CTEReadSingleIntParameter(ParametersHandle, ANSI_IF_VXD("Break"), 0, 0)) // disabled by default
|
||
{
|
||
KdPrint (("Nbt.DriverEntry: Registry-set Break!\n"));
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
ZwClose(ParametersHandle);
|
||
ZwClose(NbtConfigHandle);
|
||
#endif // _PNP_POWER_DBG_
|
||
|
||
TdiInitialize();
|
||
|
||
//
|
||
// get the file system process for NBT since we need to know this for
|
||
// allocating and freeing handles
|
||
//
|
||
NbtFspProcess =(PEPROCESS)PsGetCurrentProcess();
|
||
|
||
//
|
||
// Initialize the Configuration data structure
|
||
//
|
||
CTEZeroMemory(&NbtConfig,sizeof(tNBTCONFIG));
|
||
|
||
NbtConfig.LoopbackIfContext = 0xffff;
|
||
|
||
// save the driver object for event logging purposes
|
||
//
|
||
NbtConfig.DriverObject = DriverObject;
|
||
|
||
// save the registry path for later use when DHCP asks us
|
||
// to re-read the registry.
|
||
//
|
||
NbtConfig.pRegistry.MaximumLength = (USHORT) RegistryPath->MaximumLength;
|
||
if (NbtConfig.pRegistry.Buffer = NbtAllocMem (RegistryPath->MaximumLength, NBT_TAG2('17')))
|
||
{
|
||
RtlCopyUnicodeString(&NbtConfig.pRegistry,RegistryPath);
|
||
}
|
||
else
|
||
{
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
//
|
||
// Initialize the driver object with this driver's entry points.
|
||
//
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)NbtDispatchCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)NbtDispatchDevCtrl;
|
||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)NbtDispatchInternalCtrl;
|
||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)NbtDispatchCleanup;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)NbtDispatchClose;
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)NbtDispatchPnP;
|
||
DriverObject->DriverUnload = NbtUnload;
|
||
|
||
//
|
||
// read in registry configuration data
|
||
//
|
||
status = NbtReadRegistry (&pBindDevices, &pExportDevices, &pAddrArray);
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
//
|
||
// There must have been some major problems with the registry, so
|
||
// we will not load!
|
||
//
|
||
DbgPrint ("Nbt.DriverEntry[1]: Not loading because of failure to read registry = <%x>\n", status);
|
||
|
||
CleanupDriverEntry (1);
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Cleanup Allocated memory
|
||
//
|
||
NbtReadRegistryCleanup (&pBindDevices, &pExportDevices, &pAddrArray);
|
||
|
||
//
|
||
// Initialize NBT global data.
|
||
//
|
||
status = InitNotOs();
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
NbtLogEvent (EVENT_NBT_NON_OS_INIT, status, 0x110);
|
||
|
||
DbgPrint ("Nbt.DriverEntry[3]: Not loading because of failure to Initialize = <%x>\n",status);
|
||
CleanupDriverEntry (3); // We may have done some partial initialization!
|
||
return (status);
|
||
}
|
||
|
||
// create some MDLs, for session sends to speed up the sends.
|
||
status = NbtInitMdlQ (&NbtConfig.SessionMdlFreeSingleList, eNBT_FREE_SESSION_MDLS);
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
DbgPrint ("Nbt.DriverEntry[4]: Not loading because of failure to init Session MDL Q = <%x>\n",status);
|
||
CleanupDriverEntry (4);
|
||
return (status);
|
||
}
|
||
|
||
// create some MDLs for datagram sends
|
||
status = NbtInitMdlQ( &NbtConfig.DgramMdlFreeSingleList, eNBT_DGRAM_MDLS);
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
DbgPrint ("Nbt.DriverEntry[4]: Not loading because of failure to init Dgram MDL Q = <%x>\n", status);
|
||
CleanupDriverEntry (4);
|
||
return (status);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------------------
|
||
//
|
||
// Create the SmbDevice object for Rdr/Srv
|
||
//
|
||
if ((NbtConfig.SMBDeviceEnabled) &&
|
||
(!(pNbtSmbDevice = NbtCreateSmbDevice())))
|
||
{
|
||
KdPrint (("Nbt.DriverEntry: Failed to create SmbDevice!\n"));
|
||
//
|
||
// Allow the initialization to succeed even if this fails!
|
||
//
|
||
}
|
||
|
||
//---------------------------------------------------------------------------------------
|
||
|
||
//
|
||
// Create the NBT device object for WINS to use
|
||
//
|
||
RtlInitUnicodeString (&ucWinsDeviceBindName, WC_WINS_DEVICE_BIND_NAME);
|
||
ucWinsDeviceBindName.MaximumLength = sizeof (WC_WINS_DEVICE_BIND_NAME);
|
||
RtlInitUnicodeString (&ucWinsDeviceExportName, WC_WINS_DEVICE_EXPORT_NAME);
|
||
ucWinsDeviceExportName.MaximumLength = sizeof (WC_WINS_DEVICE_EXPORT_NAME);
|
||
|
||
//
|
||
// Try to export a DeviceObject for Wins, but do not add it to the list
|
||
// of devices which we notify TDI about
|
||
// Do not care about status because we want to continue even if we fail
|
||
//
|
||
status = NbtAllocAndInitDevice (&ucWinsDeviceBindName,
|
||
&ucWinsDeviceExportName,
|
||
&pWinsDeviceContext,
|
||
NBT_DEVICE_WINS);
|
||
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
DbgPrint ("Nbt.DriverEntry[5]: Not loading because of failure to create pWinsDevContext = <%x>\n",
|
||
status);
|
||
CleanupDriverEntry (5);
|
||
return (status);
|
||
}
|
||
status = NbtCreateAdminSecurityDescriptor(&pWinsDeviceContext->DeviceObject);
|
||
ASSERT(NT_SUCCESS(status));
|
||
|
||
pWinsDeviceContext->IpAddress = 0;
|
||
pWinsDeviceContext->DeviceRegistrationHandle = NULL;
|
||
pWinsDeviceContext->NetAddressRegistrationHandle = NULL;
|
||
pWinsDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
//---------------------------------------------------------------------------------------
|
||
|
||
#ifdef RASAUTODIAL
|
||
//
|
||
// Get the automatic connection driver
|
||
// entry points.
|
||
//
|
||
NbtAcdBind();
|
||
#endif
|
||
|
||
//---------------------------------------------------------------------------------------
|
||
|
||
//
|
||
// Register ourselves as a Provider with Tdi
|
||
//
|
||
RtlInitUnicodeString(&ucNetBTProviderName, WC_NETBT_PROVIDER_NAME);
|
||
ucNetBTProviderName.MaximumLength = sizeof (WC_NETBT_PROVIDER_NAME);
|
||
status = TdiRegisterProvider (&ucNetBTProviderName, &TdiProviderHandle);
|
||
if (NT_SUCCESS (status))
|
||
{
|
||
//
|
||
// Register our Handlers with TDI
|
||
//
|
||
RtlInitUnicodeString(&ucNetBTClientName, WC_NETBT_CLIENT_NAME);
|
||
ucNetBTClientName.MaximumLength = sizeof (WC_NETBT_CLIENT_NAME);
|
||
RtlZeroMemory(&TdiClientInterface, sizeof(TdiClientInterface));
|
||
|
||
TdiClientInterface.MajorTdiVersion = MAJOR_TDI_VERSION;
|
||
TdiClientInterface.MinorTdiVersion = MINOR_TDI_VERSION;
|
||
TdiClientInterface.ClientName = &ucNetBTClientName;
|
||
TdiClientInterface.AddAddressHandlerV2 = TdiAddressArrival;
|
||
TdiClientInterface.DelAddressHandlerV2 = TdiAddressDeletion;
|
||
TdiClientInterface.BindingHandler = TdiBindHandler;
|
||
TdiClientInterface.PnPPowerHandler = TdiPnPPowerHandler;
|
||
|
||
status = TdiRegisterPnPHandlers (&TdiClientInterface, sizeof(TdiClientInterface), &TdiClientHandle);
|
||
if (!NT_SUCCESS (status))
|
||
{
|
||
TdiDeregisterProvider (TdiProviderHandle);
|
||
TdiProviderHandle = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TdiProviderHandle = NULL;
|
||
}
|
||
|
||
if (!NT_SUCCESS (status))
|
||
{
|
||
DbgPrint ("Nbt.DriverEntry[6]: Not loading because of error = <%x>\n", status);
|
||
CleanupDriverEntry (6);
|
||
}
|
||
|
||
//
|
||
// Return to the caller.
|
||
//
|
||
return (status);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
NbtDispatchCleanup(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the NBT 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;
|
||
PIO_STACK_LOCATION pIrpSp;
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
|
||
CTEPagedCode();
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
ASSERT(pIrpSp->MajorFunction == IRP_MJ_CLEANUP);
|
||
|
||
pDeviceContext = (tDEVICECONTEXT *)Device;
|
||
if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE))
|
||
{
|
||
// IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchCleanup: Short-Ckt request --Device=<%x>, Context=<%x>, Context2=<%x>\n",
|
||
pDeviceContext, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2));
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
pIrp->IoStatus.Status = status;
|
||
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
||
return (status);
|
||
}
|
||
|
||
// look at the context value that NBT put into the FSContext2 value to
|
||
// decide what to do
|
||
switch ((USHORT)pIrpSp->FileObject->FsContext2)
|
||
{
|
||
case NBT_ADDRESS_TYPE:
|
||
// the client is closing the address file, so we must cleanup
|
||
// and memory blocks associated with it.
|
||
status = NTCleanUpAddress(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case NBT_CONNECTION_TYPE:
|
||
// the client is closing a connection, so we must clean up any
|
||
// memory blocks associated with it.
|
||
status = NTCleanUpConnection(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case NBT_WINS_TYPE:
|
||
//
|
||
// This is synchronous with the Wins NtClose operation
|
||
//
|
||
status = NTCleanUpWinsAddr (pDeviceContext, pIrp);
|
||
break;
|
||
|
||
case NBT_CONTROL_TYPE:
|
||
// there is nothing to do here....
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
/*
|
||
* complete the i/o successfully.
|
||
*/
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Complete the Irp
|
||
//
|
||
ReturnIrp(pIrp, status);
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
} // DispatchCleanup
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
NbtDispatchClose(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the NBT 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 pIrpSp;
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
|
||
CTEPagedCode();
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
ASSERT(pIrpSp->MajorFunction == IRP_MJ_CLOSE);
|
||
|
||
pDeviceContext = (tDEVICECONTEXT *)Device;
|
||
if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE))
|
||
{
|
||
// IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchClose: Short-Ckt request -- Device=<%x>, Context=<%x>, Context2=<%x>\n",
|
||
pDeviceContext, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2));
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
pIrp->IoStatus.Status = status;
|
||
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
||
return (status);
|
||
}
|
||
|
||
//
|
||
// close operations are synchronous.
|
||
//
|
||
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
||
pIrp->IoStatus.Information = 0;
|
||
|
||
switch (PtrToUlong(pIrpSp->FileObject->FsContext2))
|
||
{
|
||
case NBT_ADDRESS_TYPE:
|
||
status = NTCloseAddress(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case NBT_CONNECTION_TYPE:
|
||
status = NTCloseConnection(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case NBT_WINS_TYPE:
|
||
//
|
||
// We don't need to set the DeviceContext here since we had
|
||
// already saved it in pWinsInfo
|
||
// This is an Asynchronous operation wrt the Wins server, hence
|
||
// we should do only minimal work in this routine -- the
|
||
// major cleanup should be in the DispatchCleanup routine
|
||
//
|
||
status = NTCloseWinsAddr(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case NBT_CONTROL_TYPE:
|
||
// the client is closing the Control Object...
|
||
// there is nothing to do here....
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
KdPrint(("Nbt:Close Received for unknown object type = %X\n",
|
||
pIrpSp->FileObject->FsContext2));
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
// NTCloseAddress can return Pending until the ref count actually gets
|
||
// to zero.
|
||
//
|
||
if (status != STATUS_PENDING)
|
||
{
|
||
ReturnIrp(pIrp, status);
|
||
}
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
} // DispatchClose
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
NbtDispatchCreate(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the NBT driver's dispatch function for IRP_MJ_CREATE
|
||
requests. It is called as a consequence of one of the following:
|
||
|
||
a. TdiOpenConnection("\Device\Nbt_Elnkii0"),
|
||
b. TdiOpenAddress("\Device\Nbt_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
|
||
pIpr->FileObject => ptr to file obj created by I/O system. NBT 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;
|
||
PIO_STACK_LOCATION pIrpSp;
|
||
PFILE_FULL_EA_INFORMATION ea, eabuf;
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
UCHAR IrpFlags;
|
||
tIPADDRESS UNALIGNED *pIpAddressU;
|
||
tIPADDRESS IpAddress;
|
||
|
||
CTEPagedCode();
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
ASSERT(pIrpSp->MajorFunction == IRP_MJ_CREATE);
|
||
|
||
//
|
||
// If this device was destroyed, then reject all opens on it.
|
||
// Ideally we would like the IO sub-system to guarantee that no
|
||
// requests come down on IoDeleted devices, but.....
|
||
//
|
||
pDeviceContext = (tDEVICECONTEXT *)Device;
|
||
if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE))
|
||
{
|
||
// IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchCreate: Short-Ckt request -- Device=<%x>, CtrlCode=<%x>\n",
|
||
pDeviceContext, pIrpSp->Parameters.DeviceIoControl.IoControlCode));
|
||
pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
||
return (STATUS_INVALID_DEVICE_STATE);
|
||
}
|
||
|
||
IrpFlags = pIrpSp->Control;
|
||
|
||
//
|
||
// set the pending flag here so that it is sure to be set BEFORE the
|
||
// completion routine gets hit.
|
||
//
|
||
pIrp->IoStatus.Information = 0;
|
||
pIrp->IoStatus.Status = STATUS_PENDING;
|
||
IoMarkIrpPending(pIrp);
|
||
|
||
/*
|
||
* was this a TdiOpenConnection() or TdiOpenAddress()?
|
||
* Get the Extended Attribute pointer and look at the text
|
||
* value passed in for a match with "TransportAddress" or
|
||
* "ConnectionContext" (in FindEa)
|
||
*/
|
||
ea = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer;
|
||
|
||
IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchCreate: Major:Minor=<%x:%x>, PFILE_FULL_EA_INFORMATION = <%x>\n",
|
||
pIrpSp->MajorFunction, pIrpSp->MinorFunction, ea));
|
||
|
||
if (!ea)
|
||
{
|
||
// a null ea means open the control object
|
||
status = NTOpenControl(pDeviceContext,pIrp);
|
||
}
|
||
else if (eabuf = FindInEA(ea, TdiConnectionContext))
|
||
{
|
||
// not allowed to pass in both a Connect Request and a Transport Address
|
||
ASSERT(!FindInEA(ea, TdiTransportAddress));
|
||
status = NTOpenConnection(pDeviceContext, pIrp, eabuf);
|
||
}
|
||
else if (eabuf = FindInEA(ea, TdiTransportAddress))
|
||
{
|
||
status = NTOpenAddr(pDeviceContext, pIrp, eabuf);
|
||
}
|
||
else if (eabuf = FindInEA(ea, WINS_INTERFACE_NAME))
|
||
{
|
||
pIpAddressU = (tIPADDRESS UNALIGNED *) &ea->EaName[ea->EaNameLength+1];
|
||
if (IpAddress = *pIpAddressU)
|
||
{
|
||
status = NTOpenWinsAddr(pDeviceContext, pIrp, IpAddress);
|
||
}
|
||
else
|
||
{
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = STATUS_INVALID_EA_NAME;
|
||
}
|
||
|
||
// complete the irp if the status is anything EXCEPT status_pending
|
||
// since the name query completion routine NTCompletIO completes pending
|
||
// open addresses
|
||
|
||
if (status != STATUS_PENDING)
|
||
{
|
||
|
||
#if DBG
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
IF_DBG(NBT_DEBUG_NAMESRV)
|
||
KdPrint(("Nbt.NbtDispatchCreate: Returning Error status = %X\n",status));
|
||
}
|
||
#endif
|
||
// reset the pending returned bit, since we are NOT returning pending
|
||
pIrpSp->Control = IrpFlags;
|
||
ReturnIrp(pIrp,status);
|
||
|
||
}
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
NbtDispatchDevCtrl(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the NBT 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_UNSUCCESSFUL;
|
||
PIO_STACK_LOCATION pIrpSp;
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
ULONG IoControlCode;
|
||
PULONG_PTR pEntryPoint;
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
ASSERT(pIrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
|
||
|
||
//
|
||
// If this device was destroyed, then reject all requests on it.
|
||
// Ideally we would like the IO sub-system to guarantee that no
|
||
// requests come down on IoDeleted devices, but.....
|
||
//
|
||
pDeviceContext = (tDEVICECONTEXT *)Device;
|
||
if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE))
|
||
{
|
||
// IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchDevCtrl: Short-Ckt request -- Device=<%x>, CtrlCode=<%x>\n",
|
||
pDeviceContext, pIrpSp->Parameters.DeviceIoControl.IoControlCode));
|
||
pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
||
return (STATUS_INVALID_DEVICE_STATE);
|
||
}
|
||
|
||
/*
|
||
* Initialize the I/O status block.
|
||
*/
|
||
pIrp->IoStatus.Status = STATUS_PENDING;
|
||
pIrp->IoStatus.Information = 0;
|
||
IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode; // Save the IoControl code
|
||
|
||
IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchDevCtrl: IoControlCode = <%x>\n",
|
||
pIrpSp->Parameters.DeviceIoControl.IoControlCode));
|
||
|
||
/*
|
||
* if possible, convert the (external) device control into internal
|
||
* format, then treat it as if it had arrived that way.
|
||
*/
|
||
if (STATUS_SUCCESS == TdiMapUserRequest(Device, pIrp, pIrpSp))
|
||
{
|
||
status = NbtDispatchInternalCtrl (Device, pIrp);
|
||
}
|
||
#if FAST_DISP
|
||
// Check if upper layer is querying for fast send path
|
||
else if (pIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER)
|
||
{
|
||
if (pEntryPoint = pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer)
|
||
{
|
||
if (pIrp->RequestorMode != KernelMode) // Bug# 120649: Make sure data + the Address type are good
|
||
{
|
||
try
|
||
{
|
||
ProbeForWrite (pEntryPoint, sizeof(PVOID *), sizeof(BYTE));
|
||
*pEntryPoint = (ULONG_PTR) NTSend;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
// status = STATUS_UNSUCCESSFUL by default
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*pEntryPoint = (ULONG_PTR) NTSend;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchDevCtrl: direct send handler query %x\n", pEntryPoint));
|
||
|
||
ReturnIrp(pIrp, status);
|
||
}
|
||
#endif
|
||
else
|
||
{
|
||
status = DispatchIoctls (pDeviceContext, pIrp, pIrpSp);
|
||
}
|
||
|
||
//
|
||
// Dereference this DeviceContext, unless it was to destroy the Device!
|
||
//
|
||
if (IoControlCode != IOCTL_NETBT_DELETE_INTERFACE)
|
||
{
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
}
|
||
|
||
return (status);
|
||
} // NbtDispatchDevCtrl
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
NbtDispatchInternalCtrl(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
PIO_STACK_LOCATION pIrpSp;
|
||
NTSTATUS status;
|
||
UCHAR IrpFlags;
|
||
|
||
pDeviceContext = (tDEVICECONTEXT *)Device;
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
ASSERT(pIrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||
|
||
//
|
||
// this check is first to optimize the Send path
|
||
//
|
||
if (pIrpSp->MinorFunction ==TDI_SEND)
|
||
{
|
||
//
|
||
// this routine decides if it should complete the pIrp or not
|
||
// It never returns status pending, so we can turn off the
|
||
// pending bit
|
||
//
|
||
status = NTSend (pDeviceContext,pIrp);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// If this device was destroyed, then reject all operations on it.
|
||
// Ideally we would like the IO sub-system to guarantee that no
|
||
// requests come down on IoDeleted devices, but.....
|
||
//
|
||
if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE))
|
||
{
|
||
// IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchInternalCtrl: Short-Ckt request -- Device=<%x>, CtrlCode=<%x>\n",
|
||
pDeviceContext, pIrpSp->Parameters.DeviceIoControl.IoControlCode));
|
||
pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
||
return (STATUS_INVALID_DEVICE_STATE);
|
||
}
|
||
|
||
IrpFlags = pIrpSp->Control;
|
||
|
||
IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchInternalCtrl: MajorFunction:MinorFunction = <%x:%x>\n",
|
||
pIrpSp->MajorFunction, pIrpSp->MinorFunction));
|
||
|
||
switch (pIrpSp->MinorFunction)
|
||
{
|
||
case TDI_ACCEPT:
|
||
MakePending(pIrp);
|
||
status = NTAccept(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case TDI_ASSOCIATE_ADDRESS:
|
||
MakePending(pIrp);
|
||
status = NTAssocAddress(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case TDI_DISASSOCIATE_ADDRESS:
|
||
MakePending(pIrp);
|
||
status = NTDisAssociateAddress(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case TDI_CONNECT:
|
||
MakePending(pIrp);
|
||
status = NTConnect(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case TDI_DISCONNECT:
|
||
MakePending(pIrp);
|
||
status = NTDisconnect(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case TDI_LISTEN:
|
||
status = NTListen(pDeviceContext,pIrp);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
break;
|
||
|
||
case TDI_QUERY_INFORMATION:
|
||
status = NTQueryInformation(pDeviceContext,pIrp);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
IF_DBG(NBT_DEBUG_NAMESRV)
|
||
KdPrint(("Nbt.NbtDispatchInternalCtrl: Bad status from NTQueryInformation = %x\n",status));
|
||
}
|
||
#endif
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
break;
|
||
|
||
case TDI_RECEIVE:
|
||
status = NTReceive(pDeviceContext,pIrp);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
|
||
break;
|
||
|
||
case TDI_RECEIVE_DATAGRAM:
|
||
status = NTReceiveDatagram(pDeviceContext,pIrp);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
break;
|
||
|
||
|
||
case TDI_SEND_DATAGRAM:
|
||
|
||
status = NTSendDatagram(pDeviceContext,pIrp);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
IF_DBG(NBT_DEBUG_NAMESRV)
|
||
KdPrint(("Nbt.NbtDispatchInternalCtrl: Bad status from NTSendDatagram = %x\n",status));
|
||
}
|
||
#endif
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
break;
|
||
|
||
case TDI_SET_EVENT_HANDLER:
|
||
MakePending(pIrp);
|
||
status = NTSetEventHandler(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
case TDI_SET_INFORMATION:
|
||
MakePending(pIrp);
|
||
status = NTSetInformation(pDeviceContext,pIrp);
|
||
break;
|
||
|
||
#if DBG
|
||
//
|
||
// 0x7f is a request by the redirector to put a "magic bullet" out on
|
||
// the wire, to trigger the Network General Sniffer.
|
||
//
|
||
case 0x7f:
|
||
KdPrint(("NBT.DispatchInternalCtrl: - 07f minor function code\n"));
|
||
ReturnIrp(pIrp, STATUS_NOT_SUPPORTED);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(STATUS_NOT_SUPPORTED);
|
||
|
||
#endif /* DBG */
|
||
|
||
default:
|
||
KdPrint(("Nbt.DispatchInternalCtrl: Invalid minor function %X\n",
|
||
pIrpSp->MinorFunction));
|
||
ReturnIrp(pIrp, STATUS_INVALID_DEVICE_REQUEST);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(STATUS_INVALID_DEVICE_REQUEST);
|
||
}
|
||
|
||
// if the returned status is pending, then we do not complete the IRP
|
||
// here since it will be completed elsewhere in the code...
|
||
//
|
||
if (status != STATUS_PENDING)
|
||
{
|
||
#if DBG
|
||
// *TODO* for debug...
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
IF_DBG(NBT_DEBUG_NAMESRV)
|
||
KdPrint(("Nbt.NbtDispatchInternalCtrl: Returning Error status = %X,MinorFunc = %X\n",
|
||
status,pIrpSp->MinorFunction));
|
||
// ASSERTMSG("An error Status reported from NBT",0L);
|
||
}
|
||
#endif
|
||
pIrpSp->Control = IrpFlags;
|
||
ReturnIrp(pIrp,status);
|
||
}
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return(status);
|
||
} // NbtDispatchInternalCtrl
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
|
||
ULONG
|
||
CompleteTimerAndWorkerRequests(
|
||
)
|
||
{
|
||
CTELockHandle OldIrq;
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
LIST_ENTRY *pTimerQEntry;
|
||
tTIMERQENTRY *pTimer;
|
||
LIST_ENTRY *pWorkerQEntry;
|
||
NBT_WORK_ITEM_CONTEXT *pContext;
|
||
PNBT_WORKER_THREAD_ROUTINE pCompletionRoutine;
|
||
ULONG NumTimerRequests = 0;
|
||
ULONG NumDelayedRequests = 0;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// First remove any active Device Contexts if they are still present
|
||
//
|
||
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
||
while (!IsListEmpty(&NbtConfig.DeviceContexts))
|
||
{
|
||
pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink, tDEVICECONTEXT, Linkage);
|
||
NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE);
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
||
NbtDestroyDevice (pDeviceContext, FALSE); // Don't wait since the Worker threads will not fire
|
||
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE);
|
||
}
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
||
|
||
if (pNbtSmbDevice)
|
||
{
|
||
NbtDestroyDevice (pNbtSmbDevice, FALSE); // Don't wait since the Worker threads will not fire
|
||
pNbtSmbDevice = NULL;
|
||
}
|
||
|
||
NbtDestroyDevice (pWinsDeviceContext, FALSE); // Don't wait since the Worker threads will not fire
|
||
|
||
StopInitTimers();
|
||
KeClearEvent (&NbtConfig.TimerQLastEvent);
|
||
|
||
//
|
||
// if any other timers are active, stop them
|
||
//
|
||
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
||
while (!IsListEmpty(&TimerQ.ActiveHead))
|
||
{
|
||
pTimerQEntry = RemoveHeadList(&TimerQ.ActiveHead);
|
||
pTimer = CONTAINING_RECORD(pTimerQEntry,tTIMERQENTRY,Linkage);
|
||
InitializeListHead (&pTimer->Linkage); // in case the Linkage is touched again
|
||
|
||
IF_DBG(NBT_DEBUG_PNP_POWER)
|
||
KdPrint (("CompleteTimerAndWorkerRequests[%d]: Completing request <%x>\n",
|
||
NumTimerRequests, pTimer));
|
||
|
||
StopTimer (pTimer, NULL, NULL);
|
||
|
||
NumTimerRequests++;
|
||
}
|
||
|
||
//
|
||
// See if there are any Timers currently executing, and if so, wait for
|
||
// them to complete
|
||
//
|
||
if (NbtConfig.NumTimersRunning)
|
||
{
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
||
status = KeWaitForSingleObject(&NbtConfig.TimerQLastEvent, // Object to wait on.
|
||
Executive, // Reason for waiting
|
||
KernelMode, // Processor mode
|
||
FALSE, // Alertable
|
||
NULL); // Timeout
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
}
|
||
else
|
||
{
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
||
}
|
||
|
||
//
|
||
// See if there are any worker threads currently executing, and if so, wait for
|
||
// them to complete
|
||
//
|
||
KeClearEvent (&NbtConfig.WorkerQLastEvent);
|
||
CTESpinLock(&NbtConfig.WorkerQLock,OldIrq);
|
||
if (NbtConfig.NumWorkerThreadsQueued)
|
||
{
|
||
CTESpinFree(&NbtConfig.WorkerQLock,OldIrq);
|
||
|
||
status = KeWaitForSingleObject(&NbtConfig.WorkerQLastEvent, // Object to wait on.
|
||
Executive, // Reason for waiting
|
||
KernelMode, // Processor mode
|
||
FALSE, // Alertable
|
||
NULL); // Timeout
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
}
|
||
else
|
||
{
|
||
CTESpinFree(&NbtConfig.WorkerQLock,OldIrq);
|
||
}
|
||
|
||
//
|
||
// Dequeue each of the requests in the Worker Queue and complete them
|
||
//
|
||
CTESpinLock(&NbtConfig.WorkerQLock,OldIrq);
|
||
while (!IsListEmpty(&NbtConfig.WorkerQList))
|
||
{
|
||
pWorkerQEntry = RemoveHeadList(&NbtConfig.WorkerQList);
|
||
pContext = CONTAINING_RECORD(pWorkerQEntry, NBT_WORK_ITEM_CONTEXT, NbtConfigLinkage);
|
||
CTESpinFree(&NbtConfig.WorkerQLock,OldIrq); // To get back to non-raised Irql!
|
||
|
||
pCompletionRoutine = pContext->WorkerRoutine;
|
||
|
||
IF_DBG(NBT_DEBUG_PNP_POWER)
|
||
KdPrint (("CompleteTimerAndWorkerRequests[%d]: Completing request <%x>\n",
|
||
NumDelayedRequests, pCompletionRoutine));
|
||
|
||
(*pCompletionRoutine) (pContext->pTracker,
|
||
pContext->pClientContext,
|
||
pContext->ClientCompletion,
|
||
pContext->pDeviceContext);
|
||
|
||
CTEMemFree ((PVOID) pContext);
|
||
|
||
NumDelayedRequests++;
|
||
//
|
||
// Acquire Lock again to check if we have completed all the requests
|
||
//
|
||
CTESpinLock(&NbtConfig.WorkerQLock,OldIrq);
|
||
}
|
||
CTESpinFree(&NbtConfig.WorkerQLock,OldIrq);
|
||
|
||
//
|
||
// Now destroy the Devices queued on the Free'ed list since there are no more Worker threads or
|
||
// Timers pending!
|
||
//
|
||
while (!IsListEmpty(&NbtConfig.DevicesAwaitingDeletion))
|
||
{
|
||
pDeviceContext = CONTAINING_RECORD(NbtConfig.DevicesAwaitingDeletion.Flink, tDEVICECONTEXT, Linkage);
|
||
ASSERT (pDeviceContext->RefCount == 0);
|
||
|
||
KdPrint(("Nbt.CompleteTimerAndWorkerRequests: *** Destroying Device *** \n\t%wZ\n",
|
||
&pDeviceContext->ExportName));
|
||
|
||
RemoveEntryList (&pDeviceContext->Linkage); // Remove the Device from the to-be-free'ed list
|
||
|
||
CTEMemFree (pDeviceContext->ExportName.Buffer);
|
||
IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
|
||
}
|
||
|
||
ASSERT (IsListEmpty(&NbtConfig.AddressHead));
|
||
KdPrint(("Nbt.CompleteTimerAndWorkerRequests: Completed <%d> Timer and <%d> Delayed requests\n",
|
||
NumTimerRequests, NumDelayedRequests));
|
||
|
||
return (NumTimerRequests + NumDelayedRequests);
|
||
}
|
||
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
VOID
|
||
NbtUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the NBT driver's dispatch function for Unload requests
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by the system.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
|
||
CTEPagedCode();
|
||
|
||
KdPrint(("Nbt.NbtUnload: Unloading ...\n"));
|
||
|
||
//
|
||
// After setting the following flag, no new requests should be queued on to
|
||
// the WorkerQ NbtConfig.WorkerQLastEvent will be set when all the current
|
||
// requests have finished executing
|
||
//
|
||
NbtConfig.Unloading = TRUE;
|
||
|
||
//
|
||
// Unbind fron the RAS driver if we were bound
|
||
//
|
||
NbtAcdUnbind ();
|
||
|
||
status = TdiDeregisterPnPHandlers(TdiClientHandle);
|
||
IF_DBG(NBT_DEBUG_PNP_POWER)
|
||
KdPrint (("NbtUnload: TdiDeregisterPnPHandlers returned <%x>\n", status));
|
||
|
||
status = TdiDeregisterProvider (TdiProviderHandle);
|
||
IF_DBG(NBT_DEBUG_PNP_POWER)
|
||
KdPrint (("NbtUnload: TdiDeregisterProvider returned <%x>\n", status));
|
||
|
||
//
|
||
// Dequeue each of the requests in the Timer and NbtConfigWorker Queues and complete them
|
||
//
|
||
CompleteTimerAndWorkerRequests();
|
||
|
||
//
|
||
// Now cleanup the rest of the static allocations
|
||
//
|
||
CleanupDriverEntry (5);
|
||
|
||
ASSERT (IsListEmpty (&NbtConfig.PendingNameQueries));
|
||
|
||
if (NbtConfig.pServerBindings) {
|
||
CTEFreeMem (NbtConfig.pServerBindings);
|
||
NbtConfig.pServerBindings = NULL;
|
||
}
|
||
|
||
if (NbtConfig.pClientBindings) {
|
||
CTEFreeMem (NbtConfig.pClientBindings);
|
||
NbtConfig.pClientBindings = NULL;
|
||
}
|
||
|
||
#ifdef _NBT_WMI_SOFTWARE_TRACING_
|
||
WPP_CLEANUP(DriverObject);
|
||
#endif
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
NTSTATUS
|
||
NbtDispatchPnP(
|
||
IN PDEVICE_OBJECT Device,
|
||
IN PIRP pIrp
|
||
)
|
||
{
|
||
tDEVICECONTEXT *pDeviceContext;
|
||
PIO_STACK_LOCATION pIrpSp, pIrpSpNext;
|
||
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
||
tCONNECTELE *pConnectEle;
|
||
tLOWERCONNECTION *pLowerConn;
|
||
KIRQL OldIrq1, OldIrq2;
|
||
PDEVICE_OBJECT pTcpDeviceObject;
|
||
PFILE_OBJECT pTcpFileObject;
|
||
tFILE_OBJECTS *pFileObjectsContext;
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
|
||
//
|
||
// If this device was destroyed, then reject all operations on it.
|
||
// Ideally we would like the IO sub-system to guarantee that no
|
||
// requests come down on IoDeleted devices, but.....
|
||
//
|
||
pDeviceContext = (tDEVICECONTEXT *)Device;
|
||
if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE))
|
||
{
|
||
IF_DBG(NBT_DEBUG_DRIVER)
|
||
KdPrint(("Nbt.NbtDispatchPnP: Short-Ckt request -- Device=<%x>\n", pDeviceContext));
|
||
pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
||
return (STATUS_INVALID_DEVICE_STATE);
|
||
}
|
||
|
||
switch (pIrpSp->MinorFunction)
|
||
{
|
||
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
||
{
|
||
if (pIrpSp->Parameters.QueryDeviceRelations.Type==TargetDeviceRelation)
|
||
{
|
||
if (PtrToUlong(pIrpSp->FileObject->FsContext2) == NBT_CONNECTION_TYPE)
|
||
{
|
||
// pass to transport to get the PDO
|
||
//
|
||
pConnectEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
|
||
if (NBT_VERIFY_HANDLE2 (pConnectEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
|
||
{
|
||
CTESpinLock(pConnectEle, OldIrq1);
|
||
|
||
pLowerConn = (tLOWERCONNECTION *)pConnectEle->pLowerConnId;
|
||
if (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN))
|
||
{
|
||
CTESpinLock(pLowerConn, OldIrq2);
|
||
NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_QUERY_DEVICE_REL);
|
||
CTESpinFree(pLowerConn, OldIrq2);
|
||
CTESpinFree(pConnectEle, OldIrq1);
|
||
|
||
if ((pTcpFileObject = pLowerConn->pFileObject) &&
|
||
(pTcpDeviceObject = IoGetRelatedDeviceObject (pLowerConn->pFileObject)))
|
||
{
|
||
//
|
||
// Simply pass the Irp on by to the Transport, and let it
|
||
// fill in the info
|
||
//
|
||
pIrpSpNext = IoGetNextIrpStackLocation (pIrp);
|
||
*pIrpSpNext = *pIrpSp;
|
||
|
||
IoSetCompletionRoutine (pIrp, NULL, NULL, FALSE, FALSE, FALSE);
|
||
pIrpSpNext->FileObject = pTcpFileObject;
|
||
pIrpSpNext->DeviceObject = pTcpDeviceObject;
|
||
|
||
status = IoCallDriver(pTcpDeviceObject, pIrp);
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
return status;
|
||
}
|
||
else
|
||
{
|
||
status = STATUS_INVALID_HANDLE;
|
||
}
|
||
NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_QUERY_DEVICE_REL, FALSE);
|
||
}
|
||
else
|
||
{
|
||
status = STATUS_CONNECTION_INVALID;
|
||
CTESpinFree(pConnectEle, OldIrq1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = STATUS_INVALID_HANDLE;
|
||
}
|
||
}
|
||
else if ( PtrToUlong(pIrpSp->FileObject->FsContext2) == NBT_ADDRESS_TYPE)
|
||
{
|
||
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
||
|
||
if ((pDeviceContext->IpAddress) &&
|
||
(pFileObjectsContext = pDeviceContext->pFileObjects) &&
|
||
(pTcpFileObject = pFileObjectsContext->pDgramFileObject) &&
|
||
(pTcpDeviceObject = pFileObjectsContext->pDgramDeviceObject))
|
||
{
|
||
pFileObjectsContext->RefCount++; // Dereferenced after the Query has completed
|
||
|
||
//
|
||
// pass the Irp to transport to get the PDO
|
||
//
|
||
pIrpSpNext = IoGetNextIrpStackLocation (pIrp);
|
||
*pIrpSpNext = *pIrpSp;
|
||
|
||
IoSetCompletionRoutine (pIrp, NULL, NULL, FALSE, FALSE, FALSE);
|
||
pIrpSpNext->FileObject = pTcpFileObject;
|
||
pIrpSpNext->DeviceObject = pTcpDeviceObject;
|
||
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
||
status = IoCallDriver(pTcpDeviceObject, pIrp);
|
||
|
||
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
||
if (--pFileObjectsContext->RefCount == 0)
|
||
{
|
||
CTEQueueForNonDispProcessing(DelayedNbtCloseFileHandles,
|
||
NULL,
|
||
pFileObjectsContext,
|
||
NULL,
|
||
NULL,
|
||
TRUE);
|
||
}
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, TRUE);
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
||
|
||
return status;
|
||
}
|
||
else
|
||
{
|
||
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ASSERT (0);
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
default:
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
ReturnIrp(pIrp, status);
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
PFILE_FULL_EA_INFORMATION
|
||
FindInEA(
|
||
IN PFILE_FULL_EA_INFORMATION start,
|
||
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:
|
||
|
||
device - ptr to device object for target device
|
||
pIrp - ptr to I/O request packet
|
||
|
||
Return Value:
|
||
|
||
pointer to the extended attribute structure, or NULL if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFILE_FULL_EA_INFORMATION eabuf;
|
||
|
||
CTEPagedCode();
|
||
|
||
//
|
||
// Bug # 225668: advance eabug ptr by typecasting it to UCHAR
|
||
//
|
||
for (eabuf = start; eabuf; eabuf = (PFILE_FULL_EA_INFORMATION) ((PUCHAR)eabuf + eabuf->NextEntryOffset))
|
||
{
|
||
if (strncmp(eabuf->EaName,wanted,eabuf->EaNameLength) == 0)
|
||
{
|
||
return eabuf;
|
||
}
|
||
|
||
if (eabuf->NextEntryOffset == 0)
|
||
{
|
||
return((PFILE_FULL_EA_INFORMATION) NULL);
|
||
}
|
||
}
|
||
return((PFILE_FULL_EA_INFORMATION) NULL);
|
||
|
||
} // FindEA
|
||
|
||
|
||
|
||
//----------------------------------------------------------------------------
|
||
VOID
|
||
ReturnIrp(
|
||
IN PIRP pIrp,
|
||
IN int status
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function completes an IRP, and arranges for return parameters,
|
||
if any, to be copied.
|
||
|
||
Although somewhat a misnomer, this function is named after a similar
|
||
function in the SpiderSTREAMS emulator.
|
||
|
||
Arguments:
|
||
|
||
pIrp - pointer to the IRP to complete
|
||
status - completion status of the IRP
|
||
|
||
Return Value:
|
||
|
||
number of bytes copied back to the user.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldlevel;
|
||
CCHAR priboost;
|
||
|
||
//
|
||
// pIrp->IoStatus.Information is meaningful only for STATUS_SUCCESS
|
||
//
|
||
|
||
// set the Irps cancel routine to null or the system may bugcheck
|
||
// with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
|
||
//
|
||
// refer to IoCancelIrp() ..\ntos\io\iosubs.c
|
||
//
|
||
IoAcquireCancelSpinLock(&oldlevel);
|
||
IoSetCancelRoutine(pIrp,NULL);
|
||
IoReleaseCancelSpinLock(oldlevel);
|
||
|
||
pIrp->IoStatus.Status = status;
|
||
|
||
priboost = (CCHAR) ((status == STATUS_SUCCESS) ?
|
||
IO_NETWORK_INCREMENT : IO_NO_INCREMENT);
|
||
|
||
IoCompleteRequest(pIrp, priboost);
|
||
|
||
return;
|
||
|
||
}
|
||
//----------------------------------------------------------------------------
|
||
VOID
|
||
MakePending(
|
||
IN PIRP pIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function marks an irp pending and sets the correct status.
|
||
|
||
Arguments:
|
||
|
||
pIrp - pointer to the IRP to complete
|
||
status - completion status of the IRP
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
IoMarkIrpPending(pIrp);
|
||
pIrp->IoStatus.Status = STATUS_PENDING;
|
||
pIrp->IoStatus.Information = 0;
|
||
|
||
}
|
||
|
||
#ifdef _NBT_WMI_SOFTWARE_TRACING_
|
||
int nbtlog_strnlen(char *p, int n)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; (i < n) && *p; i++, p++) {
|
||
}
|
||
|
||
return i;
|
||
}
|
||
#endif
|