mirror of https://github.com/lianthony/NT4.0
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.
2103 lines
57 KiB
2103 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Ntutil.c
|
|
|
|
Abstract:
|
|
|
|
This file contains a number of utility and support routines that are
|
|
NT specific.
|
|
|
|
|
|
Author:
|
|
|
|
Jim Stewart (Jimst) 10-2-92
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "nbtprocs.h"
|
|
#include "stdio.h"
|
|
#include <ntddtcp.h>
|
|
#undef uint // undef to avoid a warning where tdiinfo.h redefines it
|
|
#include <tdiinfo.h>
|
|
#include <ipinfo.h>
|
|
|
|
NTSTATUS
|
|
CreateControlObject(
|
|
tNBTCONFIG *pConfig);
|
|
|
|
NTSTATUS
|
|
IfNotAnyLowerConnections(
|
|
IN tDEVICECONTEXT *pDeviceContext
|
|
);
|
|
NTSTATUS
|
|
NbtProcessDhcpRequest(
|
|
tDEVICECONTEXT *pDeviceContext);
|
|
VOID
|
|
GetExtendedAttributes(
|
|
tDEVICECONTEXT *pDeviceContext
|
|
);
|
|
|
|
PSTRM_PROCESSOR_LOG LogAlloc ;
|
|
PSTRM_PROCESSOR_LOG LogFree ;
|
|
|
|
|
|
//******************* Pageable Routine Declarations ****************
|
|
#ifdef ALLOC_PRAGMA
|
|
#ifdef _PNP_POWER
|
|
#pragma CTEMakePageable(PAGE, NbtCreateDeviceObject)
|
|
#else // _PNP_POWER
|
|
#pragma CTEMakePageable(INIT, NbtCreateDeviceObject)
|
|
#endif // _PNP_POWER
|
|
#pragma CTEMakePageable(PAGE, CreateControlObject)
|
|
#pragma CTEMakePageable(PAGE, NbtInitConnQ)
|
|
#pragma CTEMakePageable(PAGE, NbtProcessDhcpRequest)
|
|
#pragma CTEMakePageable(PAGE, NbtCreateAddressObjects)
|
|
#pragma CTEMakePageable(PAGE, GetExtendedAttributes)
|
|
#pragma CTEMakePageable(PAGE, ConvertToUlong)
|
|
#pragma CTEMakePageable(PAGE, NbtInitMdlQ)
|
|
#pragma CTEMakePageable(PAGE, NTZwCloseFile)
|
|
#pragma CTEMakePageable(PAGE, NTReReadRegistry)
|
|
#pragma CTEMakePageable(PAGE, SaveClientSecurity)
|
|
#endif
|
|
//******************* Pageable Routine Declarations ****************
|
|
|
|
ulong
|
|
GetUnique32BitValue(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns a reasonably unique 32-bit number based on the system clock.
|
|
In NT, we take the current system time, convert it to milliseconds,
|
|
and return the low 32 bits.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A reasonably unique 32-bit value.
|
|
|
|
--*/
|
|
|
|
{
|
|
LARGE_INTEGER ntTime, tmpTime;
|
|
|
|
KeQuerySystemTime(&ntTime);
|
|
|
|
tmpTime = CTEConvert100nsToMilliseconds(ntTime);
|
|
|
|
return(tmpTime.LowPart);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
NbtCreateDeviceObject(
|
|
PDRIVER_OBJECT DriverObject,
|
|
tNBTCONFIG *pConfig,
|
|
PUNICODE_STRING pucBindName,
|
|
PUNICODE_STRING pucExportName,
|
|
tADDRARRAY *pAddrs,
|
|
PUNICODE_STRING pucRegistryPath,
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
BOOLEAN fReuse,
|
|
#endif
|
|
tDEVICECONTEXT **ppDeviceContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes a Driver Object from the device object passed
|
|
in and the name of the driver object passed in. After the Driver Object
|
|
has been created, clients can "Open" the driver by that name.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
status - the outcome
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
tDEVICECONTEXT *pDeviceContext;
|
|
ULONG LinkOffset;
|
|
ULONG ulIpAddress;
|
|
ULONG ulSubnetMask;
|
|
#ifdef _PNP_POWER
|
|
PUCHAR Buffer;
|
|
#endif // _PNP_POWER
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
BOOLEAN fIsItReused=FALSE;
|
|
#endif
|
|
CTELockHandle OldIrq1;
|
|
|
|
CTEPagedCode();
|
|
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
//
|
|
// If we can re-use some of the earlier devices, so be it....
|
|
// This will go away when base supports IoDeleteDevice properly.
|
|
//
|
|
if (fReuse) {
|
|
LIST_ENTRY *pEntry;
|
|
|
|
CTESpinLock(&NbtConfig, OldIrq1);
|
|
if (!IsListEmpty(&NbtConfig.FreeDevCtx)) {
|
|
pEntry = RemoveHeadList( &NbtConfig.FreeDevCtx);
|
|
|
|
DeviceObject = (PDEVICE_OBJECT) CONTAINING_RECORD( pEntry,
|
|
tDEVICECONTEXT,
|
|
FreeLinkage);
|
|
|
|
KdPrint(("Re-using device @ %lx, bind: %ws\n", DeviceObject, ((tDEVICECONTEXT *)DeviceObject)->BindName.Buffer));
|
|
|
|
//
|
|
// Re-use the name and update the value returned to the user - we shd decrement
|
|
// the global ptr too, but we might hit some other (valid) device the next time on.
|
|
//
|
|
pucBindName->MaximumLength = ((tDEVICECONTEXT *)DeviceObject)->BindName.MaximumLength;
|
|
RtlCopyUnicodeString(pucBindName, &((tDEVICECONTEXT *)DeviceObject)->BindName);
|
|
|
|
pucExportName->MaximumLength = ((tDEVICECONTEXT *)DeviceObject)->ExportName.MaximumLength;
|
|
RtlCopyUnicodeString(pucExportName, &((tDEVICECONTEXT *)DeviceObject)->ExportName);
|
|
CTEMemFree( pDeviceContext->ExportName.Buffer );
|
|
|
|
CTESpinFree(&NbtConfig, OldIrq1);
|
|
|
|
fIsItReused = TRUE;
|
|
#ifdef _PNP_POWER
|
|
Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w'));
|
|
|
|
if ( Buffer == NULL )
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES ;
|
|
}
|
|
#endif // _PNP_POWER
|
|
goto Reuse;
|
|
}
|
|
|
|
fIsItReused = FALSE;
|
|
CTESpinFree(&NbtConfig, OldIrq1);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _PNP_POWER
|
|
Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w'));
|
|
|
|
if ( Buffer == NULL )
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES ;
|
|
}
|
|
#endif // _PNP_POWER
|
|
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // Driver Object
|
|
sizeof(tDEVICECONTEXT) - sizeof(DRIVER_OBJECT), //Device Extension
|
|
pucExportName, // Device Name
|
|
FILE_DEVICE_NBT, // Device type 0x32 for now...
|
|
0, //Device Characteristics
|
|
FALSE, //Exclusive
|
|
&DeviceObject );
|
|
|
|
if (!NT_SUCCESS( status ))
|
|
{
|
|
KdPrint(("Failed to create the Export Device, status=%X\n",status));
|
|
*ppDeviceContext = NULL;
|
|
#ifdef _PNP_POWER
|
|
CTEMemFree ( Buffer );
|
|
#endif // _PNP_POWER
|
|
return status;
|
|
}
|
|
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
Reuse:
|
|
#endif
|
|
|
|
*ppDeviceContext = pDeviceContext = (tDEVICECONTEXT *)DeviceObject;
|
|
|
|
//
|
|
// zero out the data structure, beyond the OS specific part
|
|
//
|
|
LinkOffset = (ULONG)(&((tDEVICECONTEXT *)0)->Linkage);
|
|
CTEZeroMemory(&pDeviceContext->Linkage,sizeof(tDEVICECONTEXT) - LinkOffset);
|
|
|
|
#ifdef _PNP_POWER
|
|
pDeviceContext->ExportName.MaximumLength = pucExportName->MaximumLength;
|
|
pDeviceContext->ExportName.Buffer = (PWSTR)Buffer;
|
|
|
|
RtlCopyUnicodeString(&pDeviceContext->ExportName,pucExportName);
|
|
|
|
pDeviceContext->BindName.MaximumLength = pucBindName->MaximumLength;
|
|
pDeviceContext->BindName.Buffer = (PWSTR)(Buffer+pucExportName->MaximumLength);
|
|
RtlCopyUnicodeString(&pDeviceContext->BindName,pucBindName);
|
|
#endif // _PNP_POWER
|
|
|
|
// initialize the pDeviceContext data structure. There is one of
|
|
// these data structured tied to each "device" that NBT exports
|
|
// to higher layers (i.e. one for each network adapter that it
|
|
// binds to.
|
|
// The initialization sets the forward link equal to the back link equal
|
|
// to the list head
|
|
InitializeListHead(&pDeviceContext->UpConnectionInUse);
|
|
InitializeListHead(&pDeviceContext->LowerConnection);
|
|
InitializeListHead(&pDeviceContext->LowerConnFreeHead);
|
|
|
|
// put a verifier value into the structure so that we can check that
|
|
// we are operating on the right data when the OS passes a device context
|
|
// to NBT
|
|
pDeviceContext->Verify = NBT_VERIFY_DEVCONTEXT;
|
|
|
|
// setup the spin lock);
|
|
CTEInitLock(&pDeviceContext->SpinLock);
|
|
|
|
pDeviceContext->LockNumber = DEVICE_LOCK;
|
|
//
|
|
// for a Bnode pAddrs is NULL
|
|
//
|
|
if (pAddrs)
|
|
{
|
|
pDeviceContext->lNameServerAddress = pAddrs->NameServerAddress;
|
|
pDeviceContext->lBackupServer = pAddrs->BackupServer;
|
|
//
|
|
// if the node type is set to Bnode by default then switch to Hnode if
|
|
// there are any WINS servers configured.
|
|
//
|
|
if ((NodeType & DEFAULT_NODE_TYPE) &&
|
|
(pAddrs->NameServerAddress || pAddrs->BackupServer))
|
|
{
|
|
NodeType = MSNODE | (NodeType & PROXY_NODE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We need to acquire this lock since we can have multiple devices
|
|
// being added simultaneously and hence we will need to have a unique
|
|
// Adapter Number for each device
|
|
//
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
|
// keep a bit mask around to keep track of this adapter number so we can
|
|
// quickly find if a given name is registered on a particular adapter,
|
|
// by a corresponding bit set in the tNAMEADDR - local hash table
|
|
// entry
|
|
//
|
|
pDeviceContext->AdapterNumber = (CTEULONGLONG)1 << NbtConfig.AdapterCount;
|
|
NbtConfig.AdapterCount++;
|
|
|
|
// add this new device context on to the List in the configuration
|
|
// data structure
|
|
InsertTailList(&pConfig->DeviceContexts,&pDeviceContext->Linkage);
|
|
|
|
if (NbtConfig.AdapterCount > 1)
|
|
{
|
|
NbtConfig.MultiHomed = TRUE;
|
|
}
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|
|
|
// increase the stack size of our device object, over that of the transport
|
|
// so that clients create Irps large enough
|
|
// to pass on to the transport below.
|
|
// In theory, we should just add 1 here, to account for out presence in the
|
|
// driver chain.
|
|
|
|
status = NbtTdiOpenControl(pDeviceContext);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
DeviceObject->StackSize = pDeviceContext->pControlDeviceObject->StackSize + 1;
|
|
}
|
|
else
|
|
{
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("Nbt!NbtTdiOpenControl returned status=%X\n",status));
|
|
return(status);
|
|
}
|
|
|
|
|
|
//
|
|
// An instance number is assigned to each device so that the service which
|
|
// creates logical devices in Nbt can re-use these devices in case it fails
|
|
// to destroy them in a prev. instance.
|
|
//
|
|
pDeviceContext->InstanceNumber = GetUnique32BitValue();
|
|
|
|
//
|
|
// To create the address objects for this device we need an address for
|
|
// TCP port 139 (session services, UDP Port 138 (datagram services)
|
|
// and UDP Port 137 (name services). The IP addresses to use for these
|
|
// port number must be found by "groveling" the registry..i.e. looking
|
|
// under each adapter in the registry for a /parameters/tcpip section
|
|
// and then pulling the IP address out of that
|
|
//
|
|
status = GetIPFromRegistry(
|
|
pucRegistryPath,
|
|
pucBindName,
|
|
&ulIpAddress,
|
|
&ulSubnetMask,
|
|
FALSE);
|
|
|
|
#ifdef _PNP_POWER
|
|
#ifdef NOTYET_PNP
|
|
if ( status == STATUS_INVALID_ADDRESS )
|
|
{
|
|
//
|
|
// This one doesn't have a valid static address. Try DHCP.
|
|
//
|
|
status = GetIPFromRegistry(
|
|
pucRegistryPath,
|
|
pucBindName,
|
|
&ulIpAddress,
|
|
&ulSubnetMask,
|
|
TRUE);
|
|
}
|
|
#endif NOTYET_PNP
|
|
#endif // _PNP_POWER
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("Nbt!GetIPFromRegistry returned status=%X\n",status));
|
|
return(status);
|
|
}
|
|
|
|
#ifdef _PNP_POWER
|
|
|
|
//
|
|
// Now, we create all devices up-front (in driverentry); so no need to open the addresses etc.
|
|
//
|
|
return(status);
|
|
#endif
|
|
|
|
// get the ip address out of the registry and open the required address
|
|
// objects with the underlying transport provider
|
|
status = NbtCreateAddressObjects(
|
|
ulIpAddress,
|
|
ulSubnetMask,
|
|
pDeviceContext);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
NbtLogEvent(EVENT_NBT_CREATE_ADDRESS,status);
|
|
|
|
KdPrint(("Failed to create the Address Object, status=%X\n",status));
|
|
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Add the "permanent" name to the local name table. This is the IP
|
|
// address of the node padded out to 16 bytes with zeros.
|
|
//
|
|
status = NbtAddPermanentName(pDeviceContext);
|
|
|
|
// this call must converse with the transport underneath to create
|
|
// connections and associate them with the session address object
|
|
status = NbtInitConnQ(
|
|
&pDeviceContext->LowerConnFreeHead,
|
|
sizeof(tLOWERCONNECTION),
|
|
NBT_NUM_INITIAL_CONNECTIONS,
|
|
pDeviceContext);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
// NEED TO PUT CODE IN HERE TO RELEASE THE DEVICE OBJECT CREATED
|
|
// ABOVE AND LOG AN ERROR...
|
|
|
|
NbtLogEvent(EVENT_NBT_CREATE_CONNECTION,status);
|
|
|
|
KdPrint(("Failed to create the Connection Queue, status=%X\n",status));
|
|
|
|
return(status);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
/*******************************************************************
|
|
|
|
NAME: NbtMarkHandlesAsStale
|
|
|
|
SYNOPSIS: Marks all open handles on this device as stale
|
|
|
|
ENTRY: DeviceContext ptr
|
|
|
|
NOTE: Should be called with NbtConfig.JointLock held.
|
|
|
|
HISTORY:
|
|
SanjayAn 11-Sept.-1996 Created
|
|
|
|
********************************************************************/
|
|
VOID
|
|
NbtMarkHandlesAsStale (
|
|
IN tDEVICECONTEXT * pDeviceContext
|
|
)
|
|
{
|
|
CTELockHandle OldIrq1;
|
|
CTELockHandle OldIrq2;
|
|
CTELockHandle OldIrq3;
|
|
CTELockHandle OldIrq4;
|
|
PLIST_ENTRY pEntry;
|
|
PLIST_ENTRY pEntry1;
|
|
PLIST_ENTRY pEntry2;
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pHead1;
|
|
PLIST_ENTRY pHead2;
|
|
tADDRESSELE *pAddressEle;
|
|
tCONNECTELE *pConnEle;
|
|
tCLIENTELE *pClient;
|
|
|
|
// go through the list of addresses, then the list of clients on each
|
|
// address and then the list of connection that are in use and those that
|
|
// are currently Listening.
|
|
//
|
|
pHead = &NbtConfig.AddressHead;
|
|
pEntry = pHead->Flink;
|
|
while (pEntry != pHead)
|
|
{
|
|
pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
|
|
|
|
CTESpinLock(pAddressEle,OldIrq2);
|
|
|
|
if (pAddressEle->pDeviceContext != pDeviceContext) {
|
|
CTESpinFree(pAddressEle,OldIrq2);
|
|
pEntry = pEntry->Flink;
|
|
continue;
|
|
}
|
|
|
|
pHead1 = &pAddressEle->ClientHead;
|
|
pEntry1 = pHead1->Flink;
|
|
while (pEntry1 != pHead1)
|
|
{
|
|
pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage);
|
|
pEntry1 = pEntry1->Flink;
|
|
|
|
CTESpinLock(pClient,OldIrq3);
|
|
|
|
ASSERT(pClient->pDeviceContext == pDeviceContext);
|
|
|
|
//
|
|
// Mark ClientEle as down so only a close is valid on it.
|
|
//
|
|
pClient->Verify = NBT_VERIFY_CLIENT_DOWN;
|
|
|
|
pHead2 = &pClient->ConnectActive;
|
|
pEntry2 = pHead2->Flink;
|
|
while (pEntry2 != pHead2)
|
|
{
|
|
//
|
|
// Mark ConnEle as down so only a close is valid on it.
|
|
//
|
|
pConnEle = CONTAINING_RECORD(pEntry2,tCONNECTELE,Linkage);
|
|
|
|
CTESpinLock(pConnEle,OldIrq4);
|
|
|
|
ASSERT(pConnEle->pDeviceContext == pDeviceContext);
|
|
|
|
pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
|
|
|
|
CTESpinFree(pConnEle,OldIrq4);
|
|
|
|
pEntry2 = pEntry2->Flink;
|
|
}
|
|
|
|
pHead2 = &pClient->ConnectActive;
|
|
pEntry2 = pHead2->Flink;
|
|
while (pEntry2 != pHead2)
|
|
{
|
|
tLISTENREQUESTS *pListenReq;
|
|
|
|
//
|
|
// Mark ConnEle as down so only a close is valid on it.
|
|
//
|
|
pListenReq = CONTAINING_RECORD(pEntry2,tLISTENREQUESTS,Linkage);
|
|
pConnEle = (tCONNECTELE *)pListenReq->pConnectEle;
|
|
|
|
CTESpinLock(pConnEle,OldIrq4);
|
|
|
|
ASSERT(pConnEle->pDeviceContext == pDeviceContext);
|
|
|
|
pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
|
|
|
|
CTESpinFree(pConnEle,OldIrq4);
|
|
|
|
pEntry2 = pEntry2->Flink;
|
|
}
|
|
CTESpinFree(pClient,OldIrq3);
|
|
}
|
|
CTESpinFree(pAddressEle,OldIrq2);
|
|
pEntry = pEntry->Flink;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: NbtDestroyDeviceObject
|
|
|
|
SYNOPSIS: Destroys the specified device
|
|
|
|
ENTRY: pBuffer - name of the device/ device ptr
|
|
|
|
HISTORY:
|
|
SanjayAn 11-Sept.-1996 Created
|
|
|
|
********************************************************************/
|
|
|
|
NTSTATUS
|
|
NbtDestroyDeviceObject(
|
|
#if 0
|
|
IN PVOID pBuffer
|
|
#endif
|
|
IN tDEVICECONTEXT * pDeviceContext
|
|
)
|
|
{
|
|
LIST_ENTRY * pEntry;
|
|
LIST_ENTRY * pHead;
|
|
tDEVICECONTEXT * pTmpDeviceContext;
|
|
tDEVICECONTEXT * pNextDeviceContext;
|
|
tCLIENTELE * pClientEle;
|
|
tADDRESSELE * pAddress;
|
|
tNAMEADDR * pNameAddr;
|
|
tCONNECTELE * pConnEle;
|
|
tLOWERCONNECTION * pLowerConn;
|
|
tTIMERQENTRY * pTimer;
|
|
COMPLETIONCLIENT pClientCompletion;
|
|
PVOID Context;
|
|
tDGRAM_SEND_TRACKING * pTracker;
|
|
CTELockHandle OldIrq;
|
|
CTELockHandle OldIrq1;
|
|
CTELockHandle OldIrq2;
|
|
int i;
|
|
tNBTCONFIG *pConfig = &NbtConfig;
|
|
WCHAR Buffer[MAX_PATH];
|
|
UNICODE_STRING ucExportName;
|
|
PUNICODE_STRING pucExportName;
|
|
|
|
#if 0
|
|
tDEVICECONTEXT * pDeviceContext;
|
|
|
|
ucExportName.MaximumLength = sizeof(Buffer);
|
|
ucExportName.Buffer = Buffer;
|
|
pucExportName = &ucExportName;
|
|
|
|
RtlInitUnicodeString(pucExportName, &((PNETBT_ADD_DEL_IF)pBuffer)->IfName[0]);
|
|
|
|
//
|
|
// Find which device is going away
|
|
// Also, find out a device object that is still active: we need that info
|
|
// to update some of the address ele's.
|
|
//
|
|
pDeviceContext = NULL;
|
|
pNextDeviceContext = NULL;
|
|
|
|
for ( pEntry = pConfig->DeviceContexts.Flink;
|
|
pEntry != &pConfig->DeviceContexts;
|
|
pEntry = pEntry->Flink )
|
|
{
|
|
pTmpDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage);
|
|
if ( !RtlCompareUnicodeString (
|
|
&pTmpDeviceContext->ExportName,
|
|
pucExportName,
|
|
FALSE))
|
|
pDeviceContext = pTmpDeviceContext;
|
|
else
|
|
pNextDeviceContext = pTmpDeviceContext;
|
|
}
|
|
#endif
|
|
|
|
if (pDeviceContext == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
if (pDeviceContext->IpAddress != 0) {
|
|
(VOID)NbtNewDhcpAddress(pDeviceContext,0,0);
|
|
}
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|
|
|
if ( --NbtConfig.AdapterCount == 1)
|
|
NbtConfig.MultiHomed = FALSE;
|
|
|
|
ASSERT(IsListEmpty(&pDeviceContext->LowerConnFreeHead));
|
|
|
|
//
|
|
// walk through all names and see if any is being registered on this
|
|
// device context: if so, stop and complete it!
|
|
//
|
|
for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
|
|
{
|
|
pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
|
|
pEntry = pHead->Flink;
|
|
while (pEntry != pHead)
|
|
{
|
|
pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
|
|
pEntry = pEntry->Flink;
|
|
|
|
if (pNameAddr->NameTypeState & STATE_RESOLVING)
|
|
{
|
|
pTimer = pNameAddr->pTimer;
|
|
|
|
//
|
|
// if the name registration was started for this name on this device
|
|
// context, stop the timer. (Completion routine will take care of
|
|
// doing registration on other device contexts if applicable)
|
|
//
|
|
if (pTimer)
|
|
{
|
|
pTracker = pTimer->Context;
|
|
ASSERT(pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
|
|
if (pTracker->pDeviceContext == pDeviceContext)
|
|
{
|
|
ASSERT(pTracker->pNameAddr == pNameAddr);
|
|
|
|
pNameAddr->pTimer = NULL;
|
|
|
|
StopTimer(pTimer,&pClientCompletion,&Context);
|
|
|
|
if (pClientCompletion)
|
|
{
|
|
(*pClientCompletion)(Context,STATUS_NETWORK_NAME_DELETED);
|
|
}
|
|
|
|
KdPrint(("DestroyDeviceObject: stopped name reg timer")) ;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// close all the TDI handles
|
|
//
|
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
CloseAddressesWithTransport(pDeviceContext);
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|
|
|
while (!IsListEmpty(&pDeviceContext->LowerConnection))
|
|
{
|
|
pEntry = RemoveHeadList(&pDeviceContext->LowerConnection);
|
|
pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
|
|
CTEMemFree( pLowerConn );
|
|
}
|
|
|
|
RemoveEntryList( &pDeviceContext->Linkage);
|
|
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
//
|
|
// IoDeleteDevice on a device with open handles is not supported currently.
|
|
// Until the base guys support this feature, we hack Netbt to never call IoDeleteDevice;
|
|
// instead we mark it as down and re-use the block on a later open.
|
|
// We also mark all open handles as invalid so we fail any request directed at them.
|
|
//
|
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|
NbtMarkHandlesAsStale(pDeviceContext);
|
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|
#endif
|
|
|
|
//
|
|
// Walk through the AddressHead list. If any addresses exist and they
|
|
// point to old device context, put the next device context. Also, update
|
|
// adapter mask to reflect that this device context is now gone.
|
|
//
|
|
KdPrint(("DestroyDeviceObject: setting AddrEle,NameAddr fields\r\n"));
|
|
pHead = pEntry = &NbtConfig.AddressHead;
|
|
while ((pEntry = pEntry->Flink) != pHead)
|
|
{
|
|
pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
|
|
ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS);
|
|
if (pAddress->pDeviceContext == pDeviceContext)
|
|
{
|
|
if (!IsListEmpty(&pConfig->DeviceContexts)) {
|
|
pAddress->pDeviceContext = CONTAINING_RECORD( pConfig->DeviceContexts.Flink, tDEVICECONTEXT, Linkage);
|
|
} else {
|
|
pAddress->pDeviceContext = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the name on this adapter; but dont release on other adapters
|
|
//
|
|
// only release the name on the net if it was not in conflict first
|
|
// This prevents name releases going out for names that were not actually
|
|
// claimed. Also, quick add names are not released on the net either.
|
|
//
|
|
if (!(pNameAddr->NameTypeState & (STATE_CONFLICT | NAMETYPE_QUICK)) &&
|
|
(pAddress->pNameAddr->Name[0] != '*') &&
|
|
(pNameAddr->AdapterMask & pDeviceContext->AdapterNumber))
|
|
{
|
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
(VOID)ReleaseNameOnNet(pAddress->pNameAddr,
|
|
NbtConfig.pScope,
|
|
pAddress,
|
|
NameReleaseDoneOnDynIf, // name released on dynamic if
|
|
NodeType,
|
|
pDeviceContext);
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mark in the device extension that this is not a valid device. Default is FALSE...
|
|
//
|
|
InterlockedIncrement(&pDeviceContext->IsDestroyed);
|
|
|
|
#ifndef _IO_DELETE_DEVICE_SUPPORTED
|
|
//
|
|
// Chain the device on the free list
|
|
//
|
|
ExInterlockedInsertTailList(&NbtConfig.FreeDevCtx,
|
|
&pDeviceContext->FreeLinkage,
|
|
&NbtConfig.SpinLock);
|
|
|
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
#else
|
|
|
|
CTEMemFree( pDeviceContext->ExportName.Buffer );
|
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
|
|
|
|
#endif
|
|
|
|
KdPrint(("DestroyDeviceObject: deleted @ %lx\n", pDeviceContext));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CreateControlObject(
|
|
tNBTCONFIG *pConfig)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates memory for the provider info block, tacks it
|
|
onto the global configuration and sets default values for each item.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
tCONTROLOBJECT *pControl;
|
|
|
|
|
|
CTEPagedCode();
|
|
pControl = (tCONTROLOBJECT *)ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(tCONTROLOBJECT));
|
|
if (!pControl)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
pControl->Verify = NBT_VERIFY_CONTROL;
|
|
|
|
// setup the spin lock);
|
|
CTEInitLock(&pControl->SpinLock);
|
|
|
|
pControl->ProviderInfo.Version = 1;
|
|
pControl->ProviderInfo.MaxSendSize = 0;
|
|
pControl->ProviderInfo.MaxConnectionUserData = 0;
|
|
|
|
// we need to get these values from the transport underneath...*TODO*
|
|
// since the RDR uses this value
|
|
pControl->ProviderInfo.MaxDatagramSize = 0;
|
|
|
|
pControl->ProviderInfo.ServiceFlags = 0;
|
|
/* pControl->ProviderInfo.TransmittedTsdus = 0;
|
|
pControl->ProviderInfo.ReceivedTsdus = 0;
|
|
pControl->ProviderInfo.TransmissionErrors = 0;
|
|
pControl->ProviderInfo.ReceiveErrors = 0;
|
|
*/
|
|
pControl->ProviderInfo.MinimumLookaheadData = 0;
|
|
pControl->ProviderInfo.MaximumLookaheadData = 0;
|
|
/* pControl->ProviderInfo.DiscardedFrames = 0;
|
|
pControl->ProviderInfo.OversizeTsdusReceived = 0;
|
|
pControl->ProviderInfo.UndersizeTsdusReceived = 0;
|
|
pControl->ProviderInfo.MulticastTsdusReceived = 0;
|
|
pControl->ProviderInfo.BroadcastTsdusReceived = 0;
|
|
pControl->ProviderInfo.MulticastTsdusTransmitted = 0;
|
|
pControl->ProviderInfo.BroadcastTsdusTransmitted = 0;
|
|
pControl->ProviderInfo.SendTimeouts = 0;
|
|
pControl->ProviderInfo.ReceiveTimeouts = 0;
|
|
pControl->ProviderInfo.ConnectionIndicationsReceived = 0;
|
|
pControl->ProviderInfo.ConnectionIndicationsAccepted = 0;
|
|
pControl->ProviderInfo.ConnectionsInitiated = 0;
|
|
pControl->ProviderInfo.ConnectionsAccepted = 0;
|
|
*/
|
|
// put a ptr to this info into the pConfig so we can locate it
|
|
// when we want to cleanup
|
|
pConfig->pControlObj = pControl;
|
|
|
|
/* KEEP THIS STUFF HERE SINCE WE MAY NEED TO ALSO CREATE PROVIDER STATS!!
|
|
*TODO*
|
|
DeviceList[i].ProviderStats.Version = 2;
|
|
DeviceList[i].ProviderStats.OpenConnections = 0;
|
|
DeviceList[i].ProviderStats.ConnectionsAfterNoRetry = 0;
|
|
DeviceList[i].ProviderStats.ConnectionsAfterRetry = 0;
|
|
DeviceList[i].ProviderStats.LocalDisconnects = 0;
|
|
DeviceList[i].ProviderStats.RemoteDisconnects = 0;
|
|
DeviceList[i].ProviderStats.LinkFailures = 0;
|
|
DeviceList[i].ProviderStats.AdapterFailures = 0;
|
|
DeviceList[i].ProviderStats.SessionTimeouts = 0;
|
|
DeviceList[i].ProviderStats.CancelledConnections = 0;
|
|
DeviceList[i].ProviderStats.RemoteResourceFailures = 0;
|
|
DeviceList[i].ProviderStats.LocalResourceFailures = 0;
|
|
DeviceList[i].ProviderStats.NotFoundFailures = 0;
|
|
DeviceList[i].ProviderStats.NoListenFailures = 0;
|
|
|
|
DeviceList[i].ProviderStats.DatagramsSent = 0;
|
|
DeviceList[i].ProviderStats.DatagramBytesSent.HighPart = 0;
|
|
DeviceList[i].ProviderStats.DatagramBytesSent.LowPart = 0;
|
|
|
|
DeviceList[i].ProviderStats.DatagramsReceived = 0;
|
|
DeviceList[i].ProviderStats.DatagramBytesReceived.HighPart = 0;
|
|
DeviceList[i].ProviderStats.DatagramBytesReceived.LowPart = 0;
|
|
|
|
DeviceList[i].ProviderStats.PacketsSent = 0;
|
|
DeviceList[i].ProviderStats.PacketsReceived = 0;
|
|
|
|
DeviceList[i].ProviderStats.DataFramesSent = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesSent.HighPart = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesSent.LowPart = 0;
|
|
|
|
DeviceList[i].ProviderStats.DataFramesReceived = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesReceived.HighPart = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesReceived.LowPart = 0;
|
|
|
|
DeviceList[i].ProviderStats.DataFramesResent = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesResent.HighPart = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesResent.LowPart = 0;
|
|
|
|
DeviceList[i].ProviderStats.DataFramesRejected = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesRejected.HighPart = 0;
|
|
DeviceList[i].ProviderStats.DataFrameBytesRejected.LowPart = 0;
|
|
|
|
DeviceList[i].ProviderStats.ResponseTimerExpirations = 0;
|
|
DeviceList[i].ProviderStats.AckTimerExpirations = 0;
|
|
DeviceList[i].ProviderStats.MaximumSendWindow = 0;
|
|
DeviceList[i].ProviderStats.AverageSendWindow = 0;
|
|
DeviceList[i].ProviderStats.PiggybackAckQueued = 0;
|
|
DeviceList[i].ProviderStats.PiggybackAckTimeouts = 0;
|
|
|
|
DeviceList[i].ProviderStats.WastedPacketSpace.HighPart = 0;
|
|
DeviceList[i].ProviderStats.WastedPacketSpace.LowPart = 0;
|
|
DeviceList[i].ProviderStats.WastedSpacePackets = 0;
|
|
DeviceList[i].ProviderStats.NumberOfResources = 0;
|
|
*/
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
IfNotAnyLowerConnections(
|
|
IN tDEVICECONTEXT *pDeviceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks each device context to see if there are any open
|
|
connections, and returns SUCCESS if there are. If the DoDisable flag
|
|
is set the list head of free lower connections is returned and the
|
|
list in the Nbtconfig structure is made empty.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
CTELockHandle OldIrq;
|
|
|
|
CTESpinLock(pDeviceContext,OldIrq);
|
|
if (!IsListEmpty(&pDeviceContext->LowerConnection))
|
|
{
|
|
CTESpinFree(pDeviceContext,OldIrq);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
CTESpinFree(pDeviceContext,OldIrq);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CloseAddressesWithTransport(
|
|
IN tDEVICECONTEXT *pDeviceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks each device context to see if there are any open
|
|
connections, and returns SUCCESS if there are.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN Attached;
|
|
CTELockHandle OldIrq;
|
|
PFILE_OBJECT pNSFileObject, pSFileObject, pDGFileObject;
|
|
|
|
CTEAttachFsp(&Attached);
|
|
|
|
//
|
|
// Check for the existence of Objects under SpinLock and
|
|
// then Close them outside of the SpinLock
|
|
//
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
if (pNSFileObject = pDeviceContext->pNameServerFileObject)
|
|
{
|
|
pDeviceContext->pNameServerFileObject = NULL;
|
|
}
|
|
if (pSFileObject = pDeviceContext->pSessionFileObject)
|
|
{
|
|
pDeviceContext->pSessionFileObject = NULL;
|
|
}
|
|
if (pDGFileObject = pDeviceContext->pDgramFileObject)
|
|
{
|
|
pDeviceContext->pDgramFileObject = NULL;
|
|
}
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
//
|
|
// Now close all the necessary objects as appropriate
|
|
//
|
|
if (pNSFileObject)
|
|
{
|
|
ObDereferenceObject((PVOID *)pNSFileObject);
|
|
ZwClose(pDeviceContext->hNameServer);
|
|
}
|
|
if (pSFileObject)
|
|
{
|
|
ObDereferenceObject((PVOID *)pSFileObject);
|
|
ZwClose(pDeviceContext->hSession);
|
|
}
|
|
if (pDGFileObject)
|
|
{
|
|
ObDereferenceObject((PVOID *)pDGFileObject);
|
|
ZwClose(pDeviceContext->hDgram);
|
|
}
|
|
|
|
CTEDetachFsp(Attached);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
NbtCreateAddressObjects(
|
|
IN ULONG IpAddress,
|
|
IN ULONG SubnetMask,
|
|
OUT tDEVICECONTEXT *pDeviceContext)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the ip address and subnet mask out of the registry
|
|
to calcuate the broadcast address. It then creates the address objects
|
|
with the transport.
|
|
|
|
Arguments:
|
|
|
|
pucRegistryPath - path to NBT config info in registry
|
|
pucBindName - name of the service to bind to.
|
|
pDeviceContext - ptr to the device context... place to store IP addr
|
|
and Broadcast address permanently
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
ULONG ValueMask;
|
|
UCHAR IpAddrByte;
|
|
|
|
CTEPagedCode();
|
|
//
|
|
// to get the broadcast address combine the IP address with the subnet mask
|
|
// to yield a value with 1's in the "local" portion and the IP address
|
|
// in the network portion
|
|
//
|
|
ValueMask = (SubnetMask & IpAddress) | (~SubnetMask & -1);
|
|
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("Broadcastaddress = %X\n",ValueMask));
|
|
|
|
//
|
|
// the registry can be configured to set the subnet broadcast address to
|
|
// -1 rather than use the actual subnet broadcast address. This code
|
|
// checks for that and sets the broadcast address accordingly.
|
|
//
|
|
if (!NbtConfig.UseRegistryBcastAddr)
|
|
{
|
|
pDeviceContext->BroadcastAddress = ValueMask;
|
|
}
|
|
else
|
|
{
|
|
pDeviceContext->BroadcastAddress = NbtConfig.RegistryBcastAddr;
|
|
}
|
|
|
|
pDeviceContext->IpAddress = IpAddress;
|
|
|
|
pDeviceContext->SubnetMask = SubnetMask;
|
|
//
|
|
// get the network number by checking the top bits in the ip address,
|
|
// looking for 0 or 10 or 110 or 1110
|
|
//
|
|
IpAddrByte = ((PUCHAR)&IpAddress)[3];
|
|
if ((IpAddrByte & 0x80) == 0)
|
|
{
|
|
// class A address - one byte netid
|
|
IpAddress &= 0xFF000000;
|
|
}
|
|
else
|
|
if ((IpAddrByte & 0xC0) ==0x80)
|
|
{
|
|
// class B address - two byte netid
|
|
IpAddress &= 0xFFFF0000;
|
|
}
|
|
else
|
|
if ((IpAddrByte & 0xE0) ==0xC0)
|
|
{
|
|
// class C address - three byte netid
|
|
IpAddress &= 0xFFFFFF00;
|
|
}
|
|
|
|
|
|
pDeviceContext->NetMask = IpAddress;
|
|
|
|
|
|
// now create the address objects.
|
|
|
|
// open the Ip Address for inbound Datagrams.
|
|
status = NbtTdiOpenAddress(
|
|
&pDeviceContext->hDgram,
|
|
&pDeviceContext->pDgramDeviceObject,
|
|
&pDeviceContext->pDgramFileObject,
|
|
pDeviceContext,
|
|
(USHORT)NBT_DATAGRAM_UDP_PORT,
|
|
pDeviceContext->IpAddress,
|
|
0); // not a TCP port
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
// open the Nameservice UDP port ..
|
|
status = NbtTdiOpenAddress(
|
|
&pDeviceContext->hNameServer,
|
|
&pDeviceContext->pNameServerDeviceObject,
|
|
&pDeviceContext->pNameServerFileObject,
|
|
pDeviceContext,
|
|
(USHORT)NBT_NAMESERVICE_UDP_PORT,
|
|
pDeviceContext->IpAddress,
|
|
0); // not a TCP port
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("Nbt: Open Session port %X\n",pDeviceContext));
|
|
|
|
// Open the TCP port for Session Services
|
|
status = NbtTdiOpenAddress(
|
|
&pDeviceContext->hSession,
|
|
&pDeviceContext->pSessionDeviceObject,
|
|
&pDeviceContext->pSessionFileObject,
|
|
pDeviceContext,
|
|
(USHORT)NBT_SESSION_TCP_PORT,
|
|
pDeviceContext->IpAddress,
|
|
TCP_FLAG | SESSION_FLAG); // TCP port
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// This will get the MAC address for a RAS connection
|
|
// which is zero until there really is a connection to
|
|
// the RAS server
|
|
//
|
|
GetExtendedAttributes(pDeviceContext);
|
|
return(status);
|
|
}
|
|
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("Unable to Open Session address with TDI, status = %X\n",status));
|
|
|
|
//
|
|
// Ensure that the Object pointers are NULLed out!
|
|
//
|
|
pDeviceContext->pSessionFileObject = NULL;
|
|
|
|
ObDereferenceObject(pDeviceContext->pNameServerFileObject);
|
|
pDeviceContext->pNameServerFileObject = NULL;
|
|
NTZwCloseFile(pDeviceContext->hNameServer);
|
|
|
|
}
|
|
ObDereferenceObject(pDeviceContext->pDgramFileObject);
|
|
pDeviceContext->pDgramFileObject = NULL;
|
|
NTZwCloseFile(pDeviceContext->hDgram);
|
|
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("Unable to Open NameServer port with TDI, status = %X\n",status));
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
GetExtendedAttributes(
|
|
tDEVICECONTEXT *pDeviceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a unicode dotted decimal to a ULONG
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
TCP_REQUEST_QUERY_INFORMATION_EX QueryReq;
|
|
UCHAR pBuffer[256];
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONG BufferSize = 256;
|
|
HANDLE event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PWSTR pName=L"Tcp";
|
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|
UNICODE_STRING DeviceName;
|
|
BOOLEAN Attached = FALSE;
|
|
HANDLE hTcp;
|
|
|
|
CTEPagedCode();
|
|
|
|
//
|
|
// Open a control channel to TCP for this IOCTL.
|
|
//
|
|
// NOTE: We cannot use the hControl in the DeviceContext since that was created in the context
|
|
// of the system process (address arrival from TCP/IP). Here, we are in the context of the service
|
|
// process (Ioctl down from DHCP) and so we need to open another control channel.
|
|
//
|
|
// NOTE: We still need to maintain the earlier call to create a control channel since that is
|
|
// used to submit TDI requests down to TCP/IP.
|
|
//
|
|
|
|
// copy device name into the unicode string
|
|
Status = CreateDeviceString(pName,&DeviceName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return;
|
|
}
|
|
InitializeObjectAttributes (
|
|
&ObjectAttributes,
|
|
&DeviceName,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|
KdPrint(("tcp device to open = %ws\n",DeviceName.Buffer));
|
|
|
|
EaBuffer = NULL;
|
|
|
|
Status = ZwCreateFile (
|
|
&hTcp,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&ObjectAttributes, // object attributes.
|
|
&IoStatusBlock, // returned status information.
|
|
NULL, // block size (unused).
|
|
FILE_ATTRIBUTE_NORMAL, // file attributes.
|
|
0,
|
|
FILE_CREATE,
|
|
0, // create options.
|
|
(PVOID)EaBuffer, // EA buffer.
|
|
0); // Ea length
|
|
|
|
|
|
CTEMemFree(DeviceName.Buffer);
|
|
|
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|
KdPrint( ("OpenControl CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status));
|
|
|
|
if ( NT_SUCCESS( Status ))
|
|
{
|
|
//
|
|
// Initialize the TDI information buffers.
|
|
//
|
|
//
|
|
// pass in the ipaddress as the first ULONG of the context array
|
|
//
|
|
*(ULONG *)QueryReq.Context = htonl(pDeviceContext->IpAddress);
|
|
|
|
QueryReq.ID.toi_entity.tei_entity = CL_NL_ENTITY;
|
|
QueryReq.ID.toi_entity.tei_instance = 0;
|
|
QueryReq.ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
QueryReq.ID.toi_type = INFO_TYPE_PROVIDER;
|
|
QueryReq.ID.toi_id = IP_INTFC_INFO_ID;
|
|
|
|
status = ZwCreateEvent(
|
|
&event,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) )
|
|
{
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Make the actual TDI call
|
|
//
|
|
|
|
status = ZwDeviceIoControlFile(
|
|
hTcp,
|
|
event,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_TCP_QUERY_INFORMATION_EX,
|
|
&QueryReq,
|
|
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
|
|
pBuffer,
|
|
BufferSize
|
|
);
|
|
|
|
//
|
|
// If the call pended and we were supposed to wait for completion,
|
|
// then wait.
|
|
//
|
|
|
|
if ( status == STATUS_PENDING )
|
|
{
|
|
status = KeWaitForSingleObject( event, Executive, KernelMode, FALSE, NULL );
|
|
|
|
ASSERT( NT_SUCCESS(status) );
|
|
}
|
|
|
|
if ( NT_SUCCESS(status) )
|
|
{
|
|
ULONG Length;
|
|
|
|
pDeviceContext->PointToPoint = ((((IPInterfaceInfo *)pBuffer)->iii_flags & IP_INTFC_FLAG_P2P) != 0);
|
|
|
|
//
|
|
// get the length of the mac address in case is is less than
|
|
// 6 bytes
|
|
//
|
|
Length = (((IPInterfaceInfo *)pBuffer)->iii_addrlength < sizeof(tMAC_ADDRESS))
|
|
? ((IPInterfaceInfo *)pBuffer)->iii_addrlength : sizeof(tMAC_ADDRESS);
|
|
|
|
CTEZeroMemory(pDeviceContext->MacAddress.Address,sizeof(tMAC_ADDRESS));
|
|
CTEMemCopy(&pDeviceContext->MacAddress.Address[0],
|
|
((IPInterfaceInfo *)pBuffer)->iii_addr,
|
|
Length);
|
|
|
|
}
|
|
|
|
status = ZwClose( event );
|
|
ASSERT( NT_SUCCESS(status) );
|
|
|
|
status = IoStatus.Status;
|
|
|
|
//
|
|
// Close the handle to TCP since we dont need it anymore; all TDI requests go thru the
|
|
// Control handle in the DeviceContext.
|
|
//
|
|
status = ZwClose( hTcp );
|
|
ASSERT( NT_SUCCESS(status) );
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("Nbt:Failed to Open the control connection to the transport, status1 = %X\n",
|
|
Status));
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
ConvertToUlong(
|
|
IN PUNICODE_STRING pucAddress,
|
|
OUT ULONG *pulValue)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a unicode dotted decimal to a ULONG
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
OEM_STRING OemAddress;
|
|
|
|
// create integer from unicode string
|
|
|
|
CTEPagedCode();
|
|
status = RtlUnicodeStringToAnsiString(&OemAddress, pucAddress, TRUE);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
status = ConvertDottedDecimalToUlong(OemAddress.Buffer,pulValue);
|
|
|
|
RtlFreeAnsiString(&OemAddress);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|
KdPrint(("ERR: Bad Dotted Decimal Ip Address(must be <=255 with 4 dots) = %ws\n",
|
|
pucAddress->Buffer));
|
|
|
|
return(status);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
NbtGetMdl(
|
|
PMDL *ppMdl,
|
|
enum eBUFFER_TYPES eBuffType)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates an Mdl.
|
|
|
|
Arguments:
|
|
|
|
ppListHead - a ptr to a ptr to the list head to add buffer to
|
|
iNumBuffers - the number of buffers to add to the queue
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
PMDL pMdl;
|
|
ULONG lBufferSize;
|
|
PVOID pBuffer;
|
|
|
|
if (NbtConfig.iCurrentNumBuff[eBuffType]
|
|
>= NbtConfig.iMaxNumBuff[eBuffType])
|
|
{
|
|
*ppMdl = NULL;
|
|
return;
|
|
}
|
|
|
|
lBufferSize = NbtConfig.iBufferSize[eBuffType];
|
|
|
|
pBuffer = NbtAllocMem((USHORT)lBufferSize,NBT_TAG('g'));
|
|
|
|
if (!pBuffer)
|
|
{
|
|
*ppMdl = NULL;
|
|
return;
|
|
}
|
|
|
|
// allocate a MDL to hold the session hdr
|
|
pMdl = IoAllocateMdl(
|
|
(PVOID)pBuffer,
|
|
lBufferSize,
|
|
FALSE, // want this to be a Primary buffer - the first in the chain
|
|
FALSE,
|
|
NULL);
|
|
|
|
*ppMdl = pMdl;
|
|
|
|
if (!pMdl)
|
|
{
|
|
CTEMemFree(pBuffer);
|
|
return;
|
|
}
|
|
|
|
// fill in part of the session hdr since it is always the same
|
|
if (eBuffType == eNBT_FREE_SESSION_MDLS)
|
|
{
|
|
((tSESSIONHDR *)pBuffer)->Flags = NBT_SESSION_FLAGS;
|
|
((tSESSIONHDR *)pBuffer)->Type = NBT_SESSION_MESSAGE;
|
|
}
|
|
else
|
|
if (eBuffType == eNBT_DGRAM_MDLS)
|
|
{
|
|
((tDGRAMHDR *)pBuffer)->Flags = FIRST_DGRAM | (NbtConfig.PduNodeType >> 10);
|
|
((tDGRAMHDR *)pBuffer)->PckOffset = 0; // not fragmented
|
|
|
|
}
|
|
|
|
// map the Mdl properly to fill in the pages portion of the MDL
|
|
MmBuildMdlForNonPagedPool(pMdl);
|
|
|
|
NbtConfig.iCurrentNumBuff[eBuffType]++;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
NbtInitMdlQ(
|
|
PSINGLE_LIST_ENTRY pListHead,
|
|
enum eBUFFER_TYPES eBuffType)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates Mdls for use later.
|
|
|
|
Arguments:
|
|
|
|
ppListHead - a ptr to a ptr to the list head to add buffer to
|
|
iNumBuffers - the number of buffers to add to the queue
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
PMDL pMdl;
|
|
|
|
|
|
CTEPagedCode();
|
|
// Initialize the list head, so the last element always points to NULL
|
|
pListHead->Next = NULL;
|
|
|
|
// create a small number first and then lis the list grow with time
|
|
for (i=0;i < NBT_INITIAL_NUM ;i++ )
|
|
{
|
|
|
|
NbtGetMdl(&pMdl,eBuffType);
|
|
if (!pMdl)
|
|
{
|
|
KdPrint(("NBT:Unable to allocate MDL at initialization time!!\n"));\
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
// put on free list
|
|
PushEntryList(pListHead,(PSINGLE_LIST_ENTRY)pMdl);
|
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
NTZwCloseFile(
|
|
IN HANDLE Handle
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This Routine handles closing a handle with NT within the context of NBT's
|
|
file system process.
|
|
|
|
Arguments:
|
|
|
|
pIrp - a ptr to an IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of the request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN Attached = FALSE;
|
|
|
|
CTEPagedCode();
|
|
//
|
|
// Attach to NBT's FSP (file system process) to free the handle since
|
|
// the handle is only valid in that process.
|
|
//
|
|
if (PsGetCurrentProcess() != NbtFspProcess)
|
|
{
|
|
KeAttachProcess(&NbtFspProcess->Pcb);
|
|
Attached = TRUE;
|
|
}
|
|
|
|
status = ZwClose(Handle);
|
|
|
|
if (Attached)
|
|
{
|
|
//
|
|
// go back to the original process
|
|
//
|
|
KeDetachProcess();
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
NTReReadRegistry(
|
|
IN tDEVICECONTEXT *pDeviceContext
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This Routine re-reads the registry values when DHCP issues the Ioctl
|
|
to do so.
|
|
|
|
Arguments:
|
|
|
|
pIrp - a ptr to an IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of the request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
tADDRARRAY *pAddrArray=NULL;
|
|
tADDRARRAY *pAddr;
|
|
tDEVICES *pBindDevices=NULL;
|
|
tDEVICES *pExportDevices=NULL;
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pEntry;
|
|
tDEVICECONTEXT *pDevContext;
|
|
|
|
CTEPagedCode();
|
|
|
|
CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
|
|
|
|
//
|
|
// BUGBUG [WishList]: We look at the whole registry in NbtAddressAdd too.
|
|
//
|
|
status = NbtReadRegistry(
|
|
&NbtConfig.pRegistry,
|
|
NULL, // Null Driver Object
|
|
&NbtConfig,
|
|
&pBindDevices,
|
|
&pExportDevices,
|
|
&pAddrArray);
|
|
|
|
if (pAddrArray)
|
|
{
|
|
ULONG i;
|
|
#if DBG
|
|
{
|
|
BOOLEAN fFound=FALSE;
|
|
|
|
//
|
|
// Loop thru the devicecontexts in the Config struct to ensure that this DeviceContext
|
|
// is actually valid.
|
|
//
|
|
// BUGBUG[WishList]:Would be good to have signatures in the structures.
|
|
//
|
|
pAddr = pAddrArray;
|
|
pHead = &NbtConfig.DeviceContexts;
|
|
pEntry = pHead;
|
|
while ((pEntry = pEntry->Flink) != pHead)
|
|
{
|
|
pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
|
|
if (pDevContext == pDeviceContext)
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(fFound == TRUE);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Figure out the Address entry by matching the BindDevice names against the
|
|
// name in the DeviceContext passed in.
|
|
//
|
|
for (i=0; i<NbtConfig.uNumDevices; i++) {
|
|
|
|
if (RtlCompareUnicodeString(&pDeviceContext->BindName,
|
|
&pBindDevices->Names[i],
|
|
FALSE) == 0) {
|
|
//
|
|
// We found a match
|
|
//
|
|
pDeviceContext->lNameServerAddress = pAddrArray[i].NameServerAddress;
|
|
pDeviceContext->lBackupServer = pAddrArray[i].BackupServer;
|
|
|
|
//
|
|
// if the node type is set to Bnode by default then switch to Hnode if
|
|
// there are any WINS servers configured.
|
|
//
|
|
if ((NodeType & DEFAULT_NODE_TYPE) &&
|
|
(pAddrArray[i].NameServerAddress || pAddrArray[i].BackupServer))
|
|
{
|
|
NodeType = MSNODE | (NodeType & PROXY);
|
|
}
|
|
|
|
IF_DBG(NBT_DEBUG_NAMESRV)
|
|
KdPrint(("NBT:Found BindName: %lx, AddrArray: %lx, i: %lx\n", pBindDevices, pAddrArray, i));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (i == NbtConfig.uNumDevices) {
|
|
KdPrint(("Nbt:Unable to find the entry corresp. to device %lx in the registry. BindDevices: %lx\n",
|
|
pDeviceContext, pBindDevices));
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Free Allocated memory
|
|
//
|
|
if (pBindDevices)
|
|
{
|
|
CTEMemFree(pBindDevices->RegistrySpace);
|
|
CTEMemFree((PVOID)pBindDevices);
|
|
}
|
|
if (pExportDevices)
|
|
{
|
|
CTEMemFree(pExportDevices->RegistrySpace);
|
|
CTEMemFree((PVOID)pExportDevices);
|
|
}
|
|
if (pAddrArray)
|
|
{
|
|
CTEMemFree((PVOID)pAddrArray);
|
|
}
|
|
|
|
CTEExReleaseResource(&NbtConfig.Resource);
|
|
|
|
if (pDeviceContext->IpAddress)
|
|
{
|
|
//
|
|
// Add the "permanent" name to the local name table. This is the IP
|
|
// address of the node padded out to 16 bytes with zeros.
|
|
//
|
|
status = NbtAddPermanentName(pDeviceContext);
|
|
|
|
if (!(NodeType & BNODE))
|
|
{
|
|
// Probably the Ip address just changed and Dhcp is informing us
|
|
// of a new Wins Server addresses, so refresh all the names to the
|
|
// new wins server
|
|
//
|
|
ReRegisterLocalNames();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no need to refresh
|
|
// on a Bnode
|
|
//
|
|
LockedStopTimer(&NbtConfig.pRefreshTimer);
|
|
}
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
NbtLogEvent(
|
|
IN ULONG EventCode,
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates an I/O error log record, fills it in and writes it
|
|
to the I/O error log.
|
|
|
|
|
|
Arguments:
|
|
|
|
EventCode - Identifies the error message.
|
|
Status - The status value to log: this value is put into the
|
|
data portion of the log message.
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The error was successfully logged..
|
|
STATUS_BUFER_OVERFLOW - The error data was too large to be logged.
|
|
STATUS_INSUFFICIENT_RESOURCES - Unable to allocate memory.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET ErrorLogEntry;
|
|
PVOID LoggingObject;
|
|
|
|
LoggingObject = NbtConfig.DriverObject;
|
|
|
|
ErrorLogEntry = IoAllocateErrorLogEntry(LoggingObject,sizeof(IO_ERROR_LOG_PACKET));
|
|
|
|
if (ErrorLogEntry == NULL)
|
|
{
|
|
IF_DBG(NBT_DEBUG_NAMESRV)
|
|
KdPrint(("Nbt:Unalbe to allocate Error Packet for Error logging\n"));
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
//
|
|
// Fill in the necessary log packet fields.
|
|
//
|
|
ErrorLogEntry->UniqueErrorValue = 0;
|
|
ErrorLogEntry->ErrorCode = EventCode;
|
|
ErrorLogEntry->NumberOfStrings = 0;
|
|
ErrorLogEntry->StringOffset = 0;
|
|
ErrorLogEntry->DumpDataSize = (USHORT)sizeof(ULONG);
|
|
ErrorLogEntry->DumpData[0] = Status;
|
|
|
|
IoWriteErrorLogEntry(ErrorLogEntry);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
#ifdef DBGMEMNBT
|
|
VOID
|
|
PadEntry(
|
|
char *EntryPtr
|
|
)
|
|
{
|
|
char *Limit;
|
|
|
|
//
|
|
// pad remainder of entry
|
|
//
|
|
Limit = EntryPtr + LOGWIDTH - 1;
|
|
ASSERT(LOGWIDTH >= (strlen(EntryPtr) + 1));
|
|
for (EntryPtr += strlen(EntryPtr);
|
|
EntryPtr != Limit;
|
|
EntryPtr++
|
|
) {
|
|
*EntryPtr = ' ';
|
|
}
|
|
*EntryPtr = '\0';
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
PVOID
|
|
CTEAllocMemDebug(
|
|
IN ULONG Size,
|
|
IN PVOID pBuffer,
|
|
IN UCHAR *File,
|
|
IN ULONG Line
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function logs getting and freeing memory.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
CCHAR CurrProc;
|
|
UCHAR LockFree;
|
|
UCHAR *EntryPtr;
|
|
char *Limit;
|
|
PUCHAR pFile;
|
|
PVOID pMem;
|
|
PSTRM_PROCESSOR_LOG Log ;
|
|
|
|
|
|
if (!pBuffer)
|
|
{
|
|
if (!LogAlloc)
|
|
{
|
|
LogAlloc = ExAllocatePool(NonPagedPool,sizeof(STRM_PROCESSOR_LOG));
|
|
LogAlloc->Index = 0;
|
|
}
|
|
Log = LogAlloc;
|
|
pMem = ExAllocatePool(NonPagedPool,Size);
|
|
}
|
|
else
|
|
{
|
|
if (!LogFree)
|
|
{
|
|
LogFree = ExAllocatePool(NonPagedPool,sizeof(STRM_PROCESSOR_LOG));
|
|
LogFree->Index = 0;
|
|
}
|
|
Log = LogFree;
|
|
pMem = pBuffer;
|
|
ExFreePool(pBuffer);
|
|
}
|
|
|
|
EntryPtr = Log->Log[Log->Index];
|
|
|
|
pFile = strrchr(File,'\\');
|
|
|
|
sprintf(EntryPtr,"%s %d %X",pFile, Line,pMem);
|
|
|
|
PadEntry(EntryPtr);
|
|
|
|
if (++(Log->Index) >= LOGSIZE)
|
|
{
|
|
Log->Index = 0;
|
|
}
|
|
//
|
|
// Mark next entry so we know where the log for this processor ends
|
|
//
|
|
EntryPtr = Log->Log[Log->Index];
|
|
sprintf(EntryPtr, "*** Last Entry");
|
|
|
|
return(pMem);
|
|
|
|
}
|
|
#endif
|
|
|
|
#if DBG
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
AcquireSpinLockDebug(
|
|
IN PKSPIN_LOCK pSpinLock,
|
|
IN PKIRQL pOldIrq,
|
|
IN UCHAR LockNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gets the spin lock, and then sets the mask in Nbtconfig, per
|
|
processor.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
CCHAR CurrProc;
|
|
UCHAR LockFree;
|
|
|
|
CTEGetLock(pSpinLock,pOldIrq);
|
|
|
|
CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
|
|
NbtConfig.CurrProc = CurrProc;
|
|
|
|
LockFree = (LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]);
|
|
if (!LockFree)
|
|
{
|
|
KdPrint(("CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n",
|
|
CurrProc,NbtConfig.CurrentLockNumber[CurrProc],LockNumber));
|
|
} \
|
|
|
|
ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree);
|
|
NbtConfig.CurrentLockNumber[CurrProc]|= LockNumber;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
FreeSpinLockDebug(
|
|
IN PKSPIN_LOCK pSpinLock,
|
|
IN KIRQL OldIrq,
|
|
IN UCHAR LockNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function clears the spin lock from the mask in Nbtconfig, per
|
|
processor and then releases the spin lock.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
CCHAR CurrProc;
|
|
|
|
CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
|
|
|
|
NbtConfig.CurrentLockNumber[CurrProc] &= ~LockNumber;
|
|
CTEFreeLock(pSpinLock,OldIrq);
|
|
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
AcquireSpinLockAtDpcDebug(
|
|
IN PKSPIN_LOCK pSpinLock,
|
|
IN UCHAR LockNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gets the spin lock, and then sets the mask in Nbtconfig, per
|
|
processor.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
CCHAR CurrProc;
|
|
UCHAR LockFree;
|
|
|
|
CTEGetLockAtDPC(pSpinLock, 0);
|
|
|
|
CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
|
|
NbtConfig.CurrProc = CurrProc;
|
|
|
|
LockFree = (LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]);
|
|
if (!LockFree)
|
|
{
|
|
KdPrint(("CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n",
|
|
CurrProc,NbtConfig.CurrentLockNumber[CurrProc],LockNumber));
|
|
} \
|
|
|
|
ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree);
|
|
NbtConfig.CurrentLockNumber[CurrProc]|= LockNumber;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
FreeSpinLockAtDpcDebug(
|
|
IN PKSPIN_LOCK pSpinLock,
|
|
IN UCHAR LockNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function clears the spin lock from the mask in Nbtconfig, per
|
|
processor and then releases the spin lock.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
CCHAR CurrProc;
|
|
|
|
CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
|
|
|
|
NbtConfig.CurrentLockNumber[CurrProc] &= ~LockNumber;
|
|
CTEFreeLockFromDPC(pSpinLock, 0);
|
|
|
|
}
|
|
#endif //if Dbg
|
|
|