mirror of https://github.com/tongzx/nt5src
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.
1754 lines
52 KiB
1754 lines
52 KiB
/*++
|
|
|
|
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
|