windows-nt/Source/XPSP1/NT/net/netbt/sys/nt/driver.c
2020-09-26 16:20:57 +08:00

1755 lines
52 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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