3074 lines
92 KiB
C
3074 lines
92 KiB
C
|
/*++
|
|||
|
|
|||
|
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 "precomp.h"
|
|||
|
#include "ntprocs.h"
|
|||
|
#include "stdio.h"
|
|||
|
#include <ntddtcp.h>
|
|||
|
#undef uint // undef to avoid a warning where tdiinfo.h redefines it
|
|||
|
#include <tcpinfo.h>
|
|||
|
#include <ipinfo.h>
|
|||
|
#include <tdiinfo.h>
|
|||
|
#include "ntddip.h" // Needed for PNETBT_PNP_RECONFIG_REQUEST
|
|||
|
#include <align.h>
|
|||
|
#include "ntutil.tmh"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
CreateControlObject(
|
|||
|
tNBTCONFIG *pConfig
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbtProcessDhcpRequest(
|
|||
|
tDEVICECONTEXT *pDeviceContext);
|
|||
|
VOID
|
|||
|
GetExtendedAttributes(
|
|||
|
tDEVICECONTEXT *pDeviceContext
|
|||
|
);
|
|||
|
|
|||
|
PSTRM_PROCESSOR_LOG LogAlloc ;
|
|||
|
PSTRM_PROCESSOR_LOG LogFree ;
|
|||
|
|
|||
|
extern tTIMERQ TimerQ;
|
|||
|
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma CTEMakePageable(PAGE, NbtAllocAndInitDevice)
|
|||
|
#pragma CTEMakePageable(PAGE, CreateControlObject)
|
|||
|
#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, DelayedNbtLogDuplicateNameEvent)
|
|||
|
#pragma CTEMakePageable(PAGE, DelayedNbtCloseFileHandles)
|
|||
|
#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
|
|||
|
NbtAllocAndInitDevice(
|
|||
|
PUNICODE_STRING pucBindName,
|
|||
|
PUNICODE_STRING pucExportName,
|
|||
|
tDEVICECONTEXT **ppDeviceContext,
|
|||
|
enum eNbtDevice DeviceType
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine mainly allocates the device object and initializes some
|
|||
|
of its fields.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PUCHAR Buffer;
|
|||
|
ULONG LinkOffset;
|
|||
|
tDEVICECONTEXT *pDeviceContext;
|
|||
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
*ppDeviceContext = NULL;
|
|||
|
|
|||
|
Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w'));
|
|||
|
if (Buffer == NULL)
|
|||
|
{
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
Status = IoCreateDevice (NbtConfig.DriverObject, // Driver Object
|
|||
|
sizeof(tDEVICECONTEXT)-sizeof(DEVICE_OBJECT), // Device Extension
|
|||
|
pucExportName, // Device Name
|
|||
|
FILE_DEVICE_NETWORK, // Device type 0x12
|
|||
|
FILE_DEVICE_SECURE_OPEN, // Device Characteristics
|
|||
|
FALSE, // Exclusive
|
|||
|
&DeviceObject);
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status ))
|
|||
|
{
|
|||
|
KdPrint(("Nbt.NbtAllocAndInitDevice: FAILed <%x> ExportDevice=%wZ\n",Status,pucExportName));
|
|||
|
CTEMemFree (Buffer);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
*ppDeviceContext = pDeviceContext = (tDEVICECONTEXT *)DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// zero out the data structure, beyond the OS specific part
|
|||
|
//
|
|||
|
LinkOffset = FIELD_OFFSET(tDEVICECONTEXT, Linkage);
|
|||
|
CTEZeroMemory (&pDeviceContext->Linkage, sizeof(tDEVICECONTEXT)-LinkOffset);
|
|||
|
|
|||
|
// 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.
|
|||
|
InitializeListHead (&pDeviceContext->Linkage); // Sets the forward link = back link = list head
|
|||
|
InitializeListHead (&pDeviceContext->UpConnectionInUse);
|
|||
|
InitializeListHead (&pDeviceContext->LowerConnection);
|
|||
|
InitializeListHead (&pDeviceContext->LowerConnFreeHead);
|
|||
|
InitializeListHead (&pDeviceContext->WaitingForInbound);
|
|||
|
#ifndef REMOVE_IF_TCPIP_FIX___GATEWAY_AFTER_NOTIFY_BUG
|
|||
|
pDeviceContext->DelayedNotification = NBT_TDI_NOACTION;
|
|||
|
KeInitializeEvent(&pDeviceContext->DelayedNotificationCompleteEvent, NotificationEvent, FALSE);
|
|||
|
#endif
|
|||
|
|
|||
|
// 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;
|
|||
|
pDeviceContext->DeviceType = DeviceType; // Default
|
|||
|
CTEInitLock(&pDeviceContext->LockInfo.SpinLock); // setup the spin lock
|
|||
|
#if DBG
|
|||
|
pDeviceContext->LockInfo.LockNumber = DEVICE_LOCK;
|
|||
|
#endif
|
|||
|
|
|||
|
pDeviceContext->RefCount = 1; // Dereferenced when the Device is destroyed
|
|||
|
// #if DBG
|
|||
|
pDeviceContext->ReferenceContexts[REF_DEV_CREATE]++;
|
|||
|
// #endif // DBG
|
|||
|
pDeviceContext->IPInterfaceContext = (ULONG)-1; // by default
|
|||
|
|
|||
|
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);
|
|||
|
KeInitializeEvent (&pDeviceContext->DeviceCleanedupEvent, NotificationEvent, FALSE);
|
|||
|
|
|||
|
pDeviceContext->EnableNagling = FALSE;
|
|||
|
|
|||
|
// IpAddress, AssignedIpAddress, and NumAdditionalIpAddresses fields should be = 0
|
|||
|
// DeviceRegistrationHandle and NetAddressRegistrationHandle should be NULL
|
|||
|
// DeviceRefreshState and WakeupPatternRefCount should also be = 0
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NTQueryIPForInterfaceInfo(
|
|||
|
tDEVICECONTEXT *pDeviceContext
|
|||
|
)
|
|||
|
{
|
|||
|
PVOID *pIPInfo;
|
|||
|
PIP_INTERFACE_INFO pIPIfInfo;
|
|||
|
ULONG BufferLen;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG NextAdapterNumber;
|
|||
|
UNICODE_STRING ucDeviceName;
|
|||
|
ULONG Input, Metric, IfContext;
|
|||
|
|
|||
|
if (NT_SUCCESS (status = NbtQueryIpHandler (pDeviceContext->pControlFileObject,
|
|||
|
IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER,
|
|||
|
(PVOID *) &pDeviceContext->pFastSend)))
|
|||
|
{
|
|||
|
BufferLen = sizeof(PVOID *);
|
|||
|
if (NT_SUCCESS (status = NbtProcessIPRequest (IOCTL_IP_GET_BESTINTFC_FUNC_ADDR,
|
|||
|
NULL, // No Input buffer
|
|||
|
0,
|
|||
|
(PVOID *) &pIPInfo,
|
|||
|
&BufferLen)))
|
|||
|
{
|
|||
|
pDeviceContext->pFastQuery = *pIPInfo;
|
|||
|
CTEMemFree (pIPInfo);
|
|||
|
pIPInfo = NULL;
|
|||
|
if (pDeviceContext->pFastQuery) {
|
|||
|
/*
|
|||
|
* Get the context for loopback IP address.
|
|||
|
*/
|
|||
|
IfContext = 0xffff;
|
|||
|
pDeviceContext->pFastQuery (ntohl(INADDR_LOOPBACK), &IfContext, &Metric);
|
|||
|
if (IfContext != 0xffff) {
|
|||
|
NbtConfig.LoopbackIfContext = IfContext;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint (("Nbt.NTQueryIPForInterfaceInfo: ERROR: <%x> pFastQuery on Device:\n\t<%wZ>!\n",
|
|||
|
status, &pDeviceContext->BindName));
|
|||
|
pDeviceContext->pFastQuery = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint (("Nbt.NTQueryIPForInterfaceInfo: ERROR:<%x>, Irql=<%d>,pFastSend on Device:\n\t<%wZ>!\n",
|
|||
|
status, KeGetCurrentIrql(), &pDeviceContext->BindName));
|
|||
|
pDeviceContext->pFastSend = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ((pDeviceContext->DeviceType == NBT_DEVICE_NETBIOSLESS) ||
|
|||
|
(pDeviceContext->DeviceType == NBT_DEVICE_CLUSTER))
|
|||
|
{
|
|||
|
//
|
|||
|
// Cluster devices do not have any real InterfaceContext -- initialized to -1 by default
|
|||
|
//
|
|||
|
// Determine the InterfaceContext for the Loopback address
|
|||
|
//
|
|||
|
if ((NT_SUCCESS (status)) &&
|
|||
|
(pDeviceContext->DeviceType == NBT_DEVICE_NETBIOSLESS))
|
|||
|
{
|
|||
|
ASSERT (pDeviceContext->pFastQuery);
|
|||
|
pDeviceContext->pFastQuery (ntohl(INADDR_LOOPBACK), &pDeviceContext->IPInterfaceContext, &Metric);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
//
|
|||
|
// Get the InterfaceContext for this adapter
|
|||
|
//
|
|||
|
BufferLen = sizeof(IP_ADAPTER_INDEX_MAP) * (NbtConfig.AdapterCount+2);
|
|||
|
status = NbtProcessIPRequest (IOCTL_IP_INTERFACE_INFO,
|
|||
|
NULL, // No Input buffer
|
|||
|
0,
|
|||
|
&pIPIfInfo,
|
|||
|
&BufferLen);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
for(NextAdapterNumber=0; NextAdapterNumber<(ULONG)pIPIfInfo->NumAdapters; NextAdapterNumber++)
|
|||
|
{
|
|||
|
ucDeviceName.Buffer = pIPIfInfo->Adapter[NextAdapterNumber].Name;
|
|||
|
ucDeviceName.Length = ucDeviceName.MaximumLength =
|
|||
|
(sizeof (WCHAR)) * wcslen(pIPIfInfo->Adapter[NextAdapterNumber].Name);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_PNP_POWER)
|
|||
|
KdPrint (("[%d/%d]\t<%wZ>\n",
|
|||
|
NextAdapterNumber+1, pIPIfInfo->NumAdapters, &ucDeviceName));
|
|||
|
|
|||
|
if (RtlCompareUnicodeString (&ucDeviceName, &pDeviceContext->BindName, TRUE) == 0)
|
|||
|
{
|
|||
|
pDeviceContext->IPInterfaceContext = pIPIfInfo->Adapter[NextAdapterNumber].Index;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
BufferLen = sizeof (ULONG);
|
|||
|
Input = pDeviceContext->IPInterfaceContext;
|
|||
|
|
|||
|
//
|
|||
|
// Query the latest WOL capabilities on this adapter!
|
|||
|
//
|
|||
|
if (NT_SUCCESS (status = NbtProcessIPRequest (IOCTL_IP_GET_WOL_CAPABILITY,
|
|||
|
&Input, // Input buffer
|
|||
|
BufferLen,
|
|||
|
(PVOID) &pIPInfo,
|
|||
|
&BufferLen)))
|
|||
|
{
|
|||
|
ASSERT (pIPInfo);
|
|||
|
pDeviceContext->WOLProperties = * ((PULONG) pIPInfo);
|
|||
|
CTEMemFree (pIPInfo);
|
|||
|
pIPInfo = NULL;
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_PNP_POWER)
|
|||
|
KdPrint (("Nbt.NTQueryIPForInterfaceInfo[GET_WOL_CAPABILITY]: <%x>, pDeviceContext=<%p>, Input=<%x>, Result=<%x>\n",status, pDeviceContext, Input, pDeviceContext->WOLProperties));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint (("Nbt.NTQueryIPForInterfaceInfo: Could not find IpInterface from [%d]:\n<%wZ>\n",
|
|||
|
(ULONG)pIPIfInfo->NumAdapters, &pDeviceContext->BindName));
|
|||
|
}
|
|||
|
|
|||
|
CTEMemFree (pIPIfInfo);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint (("Nbt.NTQueryIPForInterfaceInfo: ERROR<%x>, No InterfaceContext for Device:<%wZ>!\n",
|
|||
|
&pDeviceContext->BindName));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtCreateDeviceObject(
|
|||
|
PUNICODE_STRING pucBindName,
|
|||
|
PUNICODE_STRING pucExportName,
|
|||
|
tADDRARRAY *pAddrs,
|
|||
|
tDEVICECONTEXT **ppDeviceContext,
|
|||
|
enum eNbtDevice DeviceType
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
For the Netbiosless device, do not insert on device list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status - the outcome
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS status;
|
|||
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|||
|
tDEVICECONTEXT *pDeviceContext;
|
|||
|
tDEVICECONTEXT *pDeviceContextOther;
|
|||
|
ULONG ulIpAddress;
|
|||
|
CTELockHandle OldIrq1;
|
|||
|
CTEULONGLONG NextAdapterMask;
|
|||
|
ULONG NextAdapterNumber;
|
|||
|
BOOLEAN fAttached = FALSE;
|
|||
|
BOOLEAN fInserted;
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
BOOLEAN fStopInitTimers = FALSE;
|
|||
|
|
|||
|
if (DeviceType != NBT_DEVICE_NETBIOSLESS)
|
|||
|
#endif
|
|||
|
{
|
|||
|
//
|
|||
|
// 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);
|
|||
|
//
|
|||
|
// Check to make sure we have not yet crossed the limit!
|
|||
|
//
|
|||
|
if (NbtConfig.AdapterCount >= NBT_MAXIMUM_BINDINGS)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
KdPrint(("Nbt.NbtCreateDeviceObject: ERROR -- Cannot add new device=<%ws>, Max=<%d> reached\n",
|
|||
|
pucBindName->Buffer, NBT_MAXIMUM_BINDINGS));
|
|||
|
|
|||
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
NbtConfig.AdapterCount++;
|
|||
|
|
|||
|
//
|
|||
|
// If this is the first Device, we need to start the Timers
|
|||
|
//
|
|||
|
if (NbtConfig.AdapterCount == 1)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
|
|||
|
status = InitTimersNotOs();
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
|||
|
//
|
|||
|
// If we failed and no one else also started the timers, then fail
|
|||
|
//
|
|||
|
if ((status != STATUS_SUCCESS) && (!(--NbtConfig.AdapterCount)))
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
KdPrint(("Nbt.NbtCreateDeviceObject: InitTimersNotOs FAILed, failing to add device %ws\n",
|
|||
|
pucBindName->Buffer));
|
|||
|
|
|||
|
NbtLogEvent (EVENT_NBT_TIMERS, status, 0x112);
|
|||
|
StopInitTimers();
|
|||
|
return status;
|
|||
|
}
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
}
|
|||
|
|
|||
|
status = NbtAllocAndInitDevice (pucBindName, pucExportName, ppDeviceContext, DeviceType);
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
KdPrint(("Nbt.NbtCreateDeviceObject: NbtAllocAndInitDevice returned status=%X\n",status));
|
|||
|
|
|||
|
//
|
|||
|
// If we failed to add the first device stop the timers
|
|||
|
//
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
|||
|
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
// SmbDevice does not affect adapter count
|
|||
|
if ((DeviceType != NBT_DEVICE_NETBIOSLESS) &&
|
|||
|
(!(--NbtConfig.AdapterCount)))
|
|||
|
#else
|
|||
|
if (!(--NbtConfig.AdapterCount))
|
|||
|
#endif
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
StopInitTimers();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
DeviceObject = (PDEVICE_OBJECT) (pDeviceContext = *ppDeviceContext);
|
|||
|
|
|||
|
//
|
|||
|
// for a Bnode pAddrs is NULL
|
|||
|
//
|
|||
|
if (pAddrs)
|
|||
|
{
|
|||
|
#ifdef MULTIPLE_WINS
|
|||
|
int i;
|
|||
|
#endif
|
|||
|
|
|||
|
pDeviceContext->lNameServerAddress = pAddrs->NameServerAddress;
|
|||
|
pDeviceContext->lBackupServer = pAddrs->BackupServer;
|
|||
|
pDeviceContext->RefreshToBackup = 0;
|
|||
|
pDeviceContext->SwitchedToBackup = 0;
|
|||
|
#ifdef MULTIPLE_WINS
|
|||
|
pDeviceContext->lNumOtherServers = pAddrs->NumOtherServers;
|
|||
|
pDeviceContext->lLastResponsive = 0;
|
|||
|
for (i = 0; i < pAddrs->NumOtherServers; i++)
|
|||
|
{
|
|||
|
pDeviceContext->lOtherServers[i] = pAddrs->Others[i];
|
|||
|
}
|
|||
|
#endif
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
pDeviceContext->NetbiosEnabled = pAddrs->NetbiosEnabled;
|
|||
|
IF_DBG(NBT_DEBUG_PNP_POWER)
|
|||
|
KdPrint(("Nbt.NbtCreateDeviceObject: %wZ NetbiosEnabled = %d\n",
|
|||
|
&pDeviceContext->ExportName, pDeviceContext->NetbiosEnabled));
|
|||
|
#endif
|
|||
|
pDeviceContext->RasProxyFlags = pAddrs->RasProxyFlags;
|
|||
|
pDeviceContext->EnableNagling = pAddrs->EnableNagling;
|
|||
|
//
|
|||
|
// 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);
|
|||
|
}
|
|||
|
}
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
else
|
|||
|
{
|
|||
|
pDeviceContext->NetbiosEnabled = TRUE;
|
|||
|
pDeviceContext->RasProxyFlags = 0;
|
|||
|
pDeviceContext->EnableNagling = FALSE;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
CTEAttachFsp(&fAttached, REF_FSP_CREATE_DEVICE);
|
|||
|
|
|||
|
status = NbtTdiOpenControl(pDeviceContext);
|
|||
|
if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
status = NTQueryIPForInterfaceInfo (pDeviceContext);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint(("Nbt.NbtCreateDeviceObject: NbtTdiOpenControl returned status=%X\n",status));
|
|||
|
}
|
|||
|
|
|||
|
CTEDetachFsp(fAttached, REF_FSP_CREATE_DEVICE);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
// 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 our presence in the
|
|||
|
// driver chain.
|
|||
|
//
|
|||
|
DeviceObject->StackSize = pDeviceContext->pControlDeviceObject->StackSize + 1;
|
|||
|
|
|||
|
//
|
|||
|
// Get an Irp for the out of resource queue (used to disconnect sessions
|
|||
|
// when really low on memory)
|
|||
|
//
|
|||
|
if (!NbtConfig.OutOfRsrc.pIrp)
|
|||
|
{
|
|||
|
NbtConfig.OutOfRsrc.pIrp = NTAllocateNbtIrp(&pDeviceContext->DeviceObject);
|
|||
|
if (NbtConfig.OutOfRsrc.pIrp)
|
|||
|
{
|
|||
|
//
|
|||
|
// allocate a dpc structure and keep it: we might need if we hit an
|
|||
|
// out-of-resource condition
|
|||
|
//
|
|||
|
NbtConfig.OutOfRsrc.pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('a'));
|
|||
|
if (!NbtConfig.OutOfRsrc.pDpc)
|
|||
|
{
|
|||
|
IoFreeIrp(NbtConfig.OutOfRsrc.pIrp);
|
|||
|
NbtConfig.OutOfRsrc.pIrp = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((!NbtConfig.OutOfRsrc.pIrp) || (!NbtConfig.OutOfRsrc.pDpc))
|
|||
|
{
|
|||
|
KdPrint(("Nbt.NbtCreateDeviceObject: Could not create OutOfRsrc Irps!\n"));
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS (status))
|
|||
|
{
|
|||
|
//
|
|||
|
// We failed somewhere, so clean up!
|
|||
|
//
|
|||
|
if (pDeviceContext->hControl)
|
|||
|
{
|
|||
|
CTEAttachFsp(&fAttached, REF_FSP_CREATE_DEVICE);
|
|||
|
ObDereferenceObject(pDeviceContext->pControlFileObject);
|
|||
|
NTZwCloseFile(pDeviceContext->hControl);
|
|||
|
pDeviceContext->pControlFileObject = NULL;
|
|||
|
pDeviceContext->hControl = NULL;
|
|||
|
CTEDetachFsp(fAttached, REF_FSP_CREATE_DEVICE);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
|||
|
//
|
|||
|
// If this was the last Device to go away, stop the timers
|
|||
|
// (SmbDevice does not affect adapter count)
|
|||
|
//
|
|||
|
if (DeviceType == NBT_DEVICE_NETBIOSLESS)
|
|||
|
{
|
|||
|
if (!(NbtConfig.AdapterCount))
|
|||
|
{
|
|||
|
fStopInitTimers = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (!(--NbtConfig.AdapterCount))
|
|||
|
{
|
|||
|
fStopInitTimers = TRUE;
|
|||
|
}
|
|||
|
else if (NbtConfig.AdapterCount == 1)
|
|||
|
{
|
|||
|
NbtConfig.MultiHomed = FALSE;
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
|
|||
|
if (fStopInitTimers)
|
|||
|
{
|
|||
|
StopInitTimers();
|
|||
|
}
|
|||
|
|
|||
|
*ppDeviceContext = NULL;
|
|||
|
CTEMemFree (pDeviceContext->ExportName.Buffer);
|
|||
|
IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
|
|||
|
|
|||
|
NbtLogEvent (EVENT_NBT_CREATE_DEVICE, status, 0x113);
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
pDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
pDeviceContext->SessionPort = NBT_SESSION_TCP_PORT;
|
|||
|
pDeviceContext->NameServerPort = NBT_NAMESERVICE_UDP_PORT;
|
|||
|
pDeviceContext->DatagramPort = NBT_DATAGRAM_UDP_PORT;
|
|||
|
RtlZeroMemory (pDeviceContext->MessageEndpoint, NETBIOS_NAME_SIZE);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// 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();
|
|||
|
|
|||
|
//
|
|||
|
// Now set the Adapter number for this device
|
|||
|
//
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
|||
|
//
|
|||
|
// See if we have a gap in the AdapterMask of the current set of Devices
|
|||
|
// which we can utilize
|
|||
|
//
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
// SmbDevice does not affect adapter count
|
|||
|
if (IsDeviceNetbiosless(pDeviceContext))
|
|||
|
{
|
|||
|
NextAdapterNumber = 0;
|
|||
|
NextAdapterMask = 0xffffffffffffffff;
|
|||
|
}
|
|||
|
else
|
|||
|
#endif
|
|||
|
{
|
|||
|
NextAdapterNumber = 1; // 0 is for the SmbDevice!
|
|||
|
NextAdapterMask = 1;
|
|||
|
fInserted = FALSE;
|
|||
|
if (!IsListEmpty(&NbtConfig.DeviceContexts))
|
|||
|
{
|
|||
|
PLIST_ENTRY pHead, pEntry;
|
|||
|
tDEVICECONTEXT *pTmpDevContext;
|
|||
|
|
|||
|
pHead = &NbtConfig.DeviceContexts;
|
|||
|
pEntry = pHead;
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
pTmpDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
|
|||
|
if (pTmpDevContext->AdapterMask > NextAdapterMask)
|
|||
|
{
|
|||
|
pDeviceContext->Linkage.Flink = pEntry;
|
|||
|
pDeviceContext->Linkage.Blink = pEntry->Blink;
|
|||
|
pEntry->Blink->Flink = &pDeviceContext->Linkage;
|
|||
|
pEntry->Blink = &pDeviceContext->Linkage;
|
|||
|
fInserted = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
NextAdapterNumber++;
|
|||
|
NextAdapterMask = (pTmpDevContext->AdapterMask) << 1;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!fInserted)
|
|||
|
{
|
|||
|
// add this new device context on to end of the List in the
|
|||
|
// configuration data structure
|
|||
|
InsertTailList(&NbtConfig.DeviceContexts, &pDeviceContext->Linkage);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NbtConfig.CurrentAdaptersMask |= NextAdapterMask;
|
|||
|
if ((1+NbtConfig.AdapterCount) > NbtConfig.RemoteCacheLen) // Add 1 for the SmbDevice
|
|||
|
{
|
|||
|
NbtConfig.RemoteCacheLen += REMOTE_CACHE_INCREMENT;
|
|||
|
}
|
|||
|
|
|||
|
// We 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->AdapterMask = NextAdapterMask;
|
|||
|
pDeviceContext->AdapterNumber = NextAdapterNumber;
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint (("Nbt.NbtCreateDeviceObject: Device=<%x>, New AdapterCount=<%d>, AdapterMask=<%lx:%lx>\n",
|
|||
|
pDeviceContext, NbtConfig.AdapterCount, NextAdapterMask));
|
|||
|
|
|||
|
if (NbtConfig.AdapterCount > 1)
|
|||
|
{
|
|||
|
NbtConfig.MultiHomed = TRUE;
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
tDEVICECONTEXT *
|
|||
|
GetDeviceWithIPAddress(
|
|||
|
tIPADDRESS IpAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine references the device with preferably the requested
|
|||
|
IP address, otherwise, it will pick the first device with
|
|||
|
a valid IP address
|
|||
|
|
|||
|
This routine must be called with the JointLock held!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
pDeviceContext
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pHead;
|
|||
|
tDEVICECONTEXT *pDeviceContext;
|
|||
|
tDEVICECONTEXT *pDeviceContextWithIp = NULL;
|
|||
|
|
|||
|
if (!IpAddress)
|
|||
|
{
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the device with this Ip address
|
|||
|
//
|
|||
|
pHead = pEntry = &NbtConfig.DeviceContexts;
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
pDeviceContext = CONTAINING_RECORD (pEntry,tDEVICECONTEXT,Linkage);
|
|||
|
if (pDeviceContext->IpAddress)
|
|||
|
{
|
|||
|
if (IpAddress == pDeviceContext->IpAddress)
|
|||
|
{
|
|||
|
return pDeviceContext;
|
|||
|
}
|
|||
|
else if (!pDeviceContextWithIp)
|
|||
|
{
|
|||
|
pDeviceContextWithIp = pDeviceContext;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Couldn't find a Device with the requested IP address!
|
|||
|
// So, in the meantime return the first valid Device with an IP address (if any)
|
|||
|
//
|
|||
|
return pDeviceContextWithIp;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
#define MAX_REFERENCES 5000
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
NBT_REFERENCE_DEVICE(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN ULONG ReferenceContext,
|
|||
|
IN BOOLEAN fLocked
|
|||
|
)
|
|||
|
{
|
|||
|
BOOLEAN fStatus;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
if (!fLocked)
|
|||
|
{
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
if (NBT_VERIFY_HANDLE (pDeviceContext, NBT_VERIFY_DEVCONTEXT))
|
|||
|
{
|
|||
|
InterlockedIncrement(&pDeviceContext->RefCount);
|
|||
|
// #if DBG
|
|||
|
pDeviceContext->ReferenceContexts[ReferenceContext]++;
|
|||
|
ASSERT (pDeviceContext->ReferenceContexts[ReferenceContext] <= MAX_REFERENCES);
|
|||
|
// #endif // DBG
|
|||
|
fStatus = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fStatus = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (!fLocked)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
return (fStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NBT_DEREFERENCE_DEVICE(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN ULONG ReferenceContext,
|
|||
|
IN BOOLEAN fLocked
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine Dereferences the DeviceContext and queues it on
|
|||
|
to the worker thread if the the Device needs to be deleted
|
|||
|
|
|||
|
This routine may be called with the JointLock held!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pContext
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
if (!fLocked)
|
|||
|
{
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (NBT_VERIFY_HANDLE2(pDeviceContext, NBT_VERIFY_DEVCONTEXT, NBT_VERIFY_DEVCONTEXT_DOWN));
|
|||
|
ASSERT (pDeviceContext->ReferenceContexts[ReferenceContext]);
|
|||
|
// #if DBG
|
|||
|
pDeviceContext->ReferenceContexts[ReferenceContext]--;
|
|||
|
// #endif // DBG
|
|||
|
|
|||
|
if (!(--pDeviceContext->RefCount))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
for (i=0; i<REF_DEV_MAX; i++)
|
|||
|
{
|
|||
|
ASSERT(0 == pDeviceContext->ReferenceContexts[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
//
|
|||
|
// We cannot delete the device directly here since we are at raised Irql
|
|||
|
//
|
|||
|
CTEQueueForNonDispProcessing( DelayedNbtDeleteDevice,
|
|||
|
NULL,
|
|||
|
pDeviceContext,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
if (!fLocked)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbtDestroyDevice(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN BOOLEAN fWait
|
|||
|
)
|
|||
|
{
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pHead;
|
|||
|
tTIMERQENTRY *pTimer;
|
|||
|
COMPLETIONCLIENT pClientCompletion;
|
|||
|
PVOID Context;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
BOOLEAN fRemoveFromSmbList = FALSE;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (!NBT_VERIFY_HANDLE(pDeviceContext, NBT_VERIFY_DEVCONTEXT))
|
|||
|
{
|
|||
|
ASSERT (NBT_VERIFY_HANDLE(pDeviceContext, NBT_VERIFY_DEVCONTEXT_DOWN));
|
|||
|
return (STATUS_INVALID_DEVICE_REQUEST);
|
|||
|
}
|
|||
|
//
|
|||
|
// First remove the Device from the NbtConfig list
|
|||
|
// (no-op for Wins and SmbDevice)
|
|||
|
//
|
|||
|
RemoveEntryList (&pDeviceContext->Linkage);
|
|||
|
if ((pDeviceContext->DeviceType != NBT_DEVICE_NETBIOSLESS) &&
|
|||
|
(pDeviceContext->IPInterfaceContext != (ULONG)-1))
|
|||
|
{
|
|||
|
if (pDeviceContext->AdapterMask & NbtConfig.ServerMask) {
|
|||
|
fRemoveFromSmbList = TRUE;
|
|||
|
NbtConfig.ServerMask &= (~pDeviceContext->AdapterMask);
|
|||
|
}
|
|||
|
NbtConfig.ClientMask &= (~pDeviceContext->AdapterMask);
|
|||
|
}
|
|||
|
|
|||
|
pDeviceContext->Verify = NBT_VERIFY_DEVCONTEXT_DOWN;
|
|||
|
//
|
|||
|
// Clear out the DeviceContext entry from the IPContext-to-Device Map
|
|||
|
//
|
|||
|
NbtConfig.CurrentAdaptersMask &= ~pDeviceContext->AdapterMask;
|
|||
|
//
|
|||
|
// Remove any pending requests in the LmHosts or Dns or CheckAddrs Q's
|
|||
|
// This has to be done immediately after we change the device
|
|||
|
// state before releasing the lock.
|
|||
|
//
|
|||
|
TimeoutLmHRequests (NULL, pDeviceContext, TRUE, &OldIrq);
|
|||
|
|
|||
|
if ((fRemoveFromSmbList) &&
|
|||
|
(pNbtSmbDevice) &&
|
|||
|
(NBT_REFERENCE_DEVICE (pNbtSmbDevice, REF_DEV_SMB_BIND, TRUE)))
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
//
|
|||
|
// Set the Session port info
|
|||
|
//
|
|||
|
if (pNbtSmbDevice->hSession)
|
|||
|
{
|
|||
|
NbtSetTcpInfo (pNbtSmbDevice->hSession,
|
|||
|
AO_OPTION_DEL_IFLIST,
|
|||
|
INFO_TYPE_ADDRESS_OBJECT,
|
|||
|
pDeviceContext->IPInterfaceContext);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now, set the same for the Datagram port
|
|||
|
//
|
|||
|
if ((pNbtSmbDevice->pFileObjects) &&
|
|||
|
(pNbtSmbDevice->pFileObjects->hDgram))
|
|||
|
{
|
|||
|
NbtSetTcpInfo (pNbtSmbDevice->pFileObjects->hDgram,
|
|||
|
AO_OPTION_DEL_IFLIST,
|
|||
|
INFO_TYPE_ADDRESS_OBJECT,
|
|||
|
pDeviceContext->IPInterfaceContext);
|
|||
|
}
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
NBT_DEREFERENCE_DEVICE (pNbtSmbDevice, REF_DEV_SMB_BIND, TRUE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we still have any timers running on this Device, stop them!
|
|||
|
//
|
|||
|
pHead = &TimerQ.ActiveHead;
|
|||
|
pEntry = pHead->Flink;
|
|||
|
while (pEntry != pHead)
|
|||
|
{
|
|||
|
pTimer = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage);
|
|||
|
if (pTimer->pDeviceContext == (PVOID) pDeviceContext)
|
|||
|
{
|
|||
|
StopTimer(pTimer,&pClientCompletion,&Context);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (pClientCompletion)
|
|||
|
{
|
|||
|
(*pClientCompletion)(Context, STATUS_TIMEOUT);
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint(("NbtDestroyDevice: stopped timer on this Device")) ;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
pEntry = pHead->Flink; // Restart from the beginning since we released the lock
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pEntry = pEntry->Flink;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Now do the Dereference which will cause this Device to be destroyed!
|
|||
|
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_CREATE, TRUE);
|
|||
|
|
|||
|
if (fWait)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
InitializeListHead (&pDeviceContext->Linkage);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_PNP_POWER)
|
|||
|
KdPrint(("Nbt.NbtDestroyDevice: Waiting on Device=<%p>:\n\t%wZ\n",
|
|||
|
pDeviceContext, &pDeviceContext->ExportName));
|
|||
|
//
|
|||
|
// Wait for all pending Timer and worker requests which have referenced this
|
|||
|
// Device to complete!
|
|||
|
//
|
|||
|
status = KeWaitForSingleObject (&pDeviceContext->DeviceCleanedupEvent, // Object to wait on.
|
|||
|
Executive, // Reason for waiting
|
|||
|
KernelMode, // Processor mode
|
|||
|
FALSE, // Alertable
|
|||
|
NULL); // Timeout
|
|||
|
ASSERT(status == STATUS_SUCCESS);
|
|||
|
|
|||
|
KdPrint(("Nbt.NbtDestroyDevice: *** Destroying Device *** \n\t%wZ\n", &pDeviceContext->ExportName));
|
|||
|
|
|||
|
CTEMemFree (pDeviceContext->ExportName.Buffer);
|
|||
|
IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Put it here so that the Cleanup routine can find this Device
|
|||
|
//
|
|||
|
InsertTailList(&NbtConfig.DevicesAwaitingDeletion,&pDeviceContext->Linkage);
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*******************************************************************
|
|||
|
|
|||
|
NAME: DelayedNbtDeleteDevice
|
|||
|
|
|||
|
SYNOPSIS: This Routine is the worker thread for Deleting the
|
|||
|
DeviceObject at PASSIVE level Irql
|
|||
|
|
|||
|
ENTRY: pDeviceContext - name of the device/ device ptr
|
|||
|
|
|||
|
Return Value: NONE
|
|||
|
|
|||
|
********************************************************************/
|
|||
|
|
|||
|
VOID
|
|||
|
DelayedNbtDeleteDevice(
|
|||
|
IN tDGRAM_SEND_TRACKING *pUnused1,
|
|||
|
IN PVOID pContext,
|
|||
|
IN PVOID pUnused2,
|
|||
|
IN tDEVICECONTEXT *pUnused3
|
|||
|
)
|
|||
|
{
|
|||
|
LIST_ENTRY * pEntry;
|
|||
|
LIST_ENTRY * pHead;
|
|||
|
LIST_ENTRY * pClientEntry;
|
|||
|
LIST_ENTRY TempList;
|
|||
|
tDEVICECONTEXT * pTmpDeviceContext;
|
|||
|
tDEVICECONTEXT * pNextDeviceContext;
|
|||
|
tCLIENTELE * pClientEle;
|
|||
|
tCLIENTELE * pLastClient;
|
|||
|
tADDRESSELE * pAddress;
|
|||
|
tADDRESSELE * pLastAddress;
|
|||
|
tNAMEADDR * pNameAddr;
|
|||
|
tCONNECTELE * pConnEle;
|
|||
|
tLOWERCONNECTION * pLowerConn;
|
|||
|
tTIMERQENTRY * pTimer;
|
|||
|
COMPLETIONCLIENT pClientCompletion;
|
|||
|
PVOID Context;
|
|||
|
tDGRAM_SEND_TRACKING * pTracker;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
CTELockHandle OldIrq1;
|
|||
|
CTELockHandle OldIrq2;
|
|||
|
int i;
|
|||
|
WCHAR Buffer[MAX_PATH];
|
|||
|
UNICODE_STRING ucExportName;
|
|||
|
PUNICODE_STRING pucExportName;
|
|||
|
BOOLEAN Attached;
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
NTSTATUS Status;
|
|||
|
#endif // _PNP_POWER_
|
|||
|
BOOLEAN fDelSmbDevice = FALSE;
|
|||
|
BOOLEAN fStopInitTimers = FALSE;
|
|||
|
BOOLEAN fNameReferenced = FALSE;
|
|||
|
tDEVICECONTEXT * pDeviceContext = (tDEVICECONTEXT *) pContext;
|
|||
|
|
|||
|
ASSERT (NBT_VERIFY_HANDLE(pDeviceContext, NBT_VERIFY_DEVCONTEXT_DOWN));
|
|||
|
|
|||
|
//
|
|||
|
// Mark in the device extension that this is not a valid device anymore
|
|||
|
//
|
|||
|
pDeviceContext->Verify += 10;
|
|||
|
|
|||
|
//
|
|||
|
// DeRegister this Device for our clients
|
|||
|
//
|
|||
|
if (pDeviceContext->NetAddressRegistrationHandle)
|
|||
|
{
|
|||
|
Status = TdiDeregisterNetAddress (pDeviceContext->NetAddressRegistrationHandle);
|
|||
|
pDeviceContext->NetAddressRegistrationHandle = NULL;
|
|||
|
NbtTrace(NBT_TRACE_PNP, ("DeregisterNetAddress: ExportName=%Z BindName=%Z status=%!status!",
|
|||
|
&pDeviceContext->ExportName, &pDeviceContext->BindName, Status));
|
|||
|
}
|
|||
|
if (pDeviceContext->DeviceRegistrationHandle)
|
|||
|
{
|
|||
|
Status = TdiDeregisterDeviceObject (pDeviceContext->DeviceRegistrationHandle);
|
|||
|
pDeviceContext->DeviceRegistrationHandle = NULL;
|
|||
|
NbtTrace(NBT_TRACE_PNP, ("DeregisterDevice: ExportName=%Z BindName=%Z status=%!status!",
|
|||
|
&pDeviceContext->ExportName, &pDeviceContext->BindName, Status));
|
|||
|
}
|
|||
|
if (!IsDeviceNetbiosless(pDeviceContext)) {
|
|||
|
NbtRemovePermanentName(pDeviceContext);
|
|||
|
}
|
|||
|
|
|||
|
if (pDeviceContext->IpAddress)
|
|||
|
{
|
|||
|
if (IsDeviceNetbiosless(pDeviceContext))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_PNP_POWER)
|
|||
|
KdPrint (("Nbt.DelayedNbtDeleteDevice: device %wZ deregistered\n",
|
|||
|
&(pDeviceContext->ExportName) ));
|
|||
|
}
|
|||
|
|
|||
|
CloseAddressesWithTransport(pDeviceContext);
|
|||
|
|
|||
|
//
|
|||
|
// Dhcp is has passed down a null IP address meaning that it has
|
|||
|
// lost the lease on the previous address, so close all connections
|
|||
|
// to the transport - pLowerConn.
|
|||
|
//
|
|||
|
CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
|
|||
|
DisableInboundConnections (pDeviceContext);
|
|||
|
CTEExReleaseResource(&NbtConfig.Resource);
|
|||
|
}
|
|||
|
|
|||
|
if (pDeviceContext->pControlFileObject)
|
|||
|
{
|
|||
|
BOOLEAN Attached;
|
|||
|
|
|||
|
CTEAttachFsp(&Attached, REF_FSP_DELETE_DEVICE);
|
|||
|
|
|||
|
ObDereferenceObject(pDeviceContext->pControlFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tDelayedNbtDeleteDevice->ObDereferenceObject\n", pDeviceContext->pControlFileObject));
|
|||
|
Status = ZwClose(pDeviceContext->hControl);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tDelayedNbtDeleteDevice->ZwClose, status = <%x>\n", pDeviceContext->hControl, Status));
|
|||
|
|
|||
|
pDeviceContext->pControlFileObject = NULL;
|
|||
|
pDeviceContext->hControl = NULL;
|
|||
|
|
|||
|
CTEDetachFsp(Attached, REF_FSP_DELETE_DEVICE);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|||
|
|
|||
|
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);
|
|||
|
|
|||
|
//
|
|||
|
// if a name registration or refresh or release 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 = pNameAddr->pTimer) &&
|
|||
|
(pTracker = pTimer->Context) &&
|
|||
|
(pTracker->pDeviceContext == pDeviceContext))
|
|||
|
{
|
|||
|
ASSERT(pTracker->pNameAddr == pNameAddr);
|
|||
|
|
|||
|
pNameAddr->pTimer = NULL;
|
|||
|
|
|||
|
StopTimer(pTimer,&pClientCompletion,&Context);
|
|||
|
|
|||
|
NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_DELETE_DEVICE);
|
|||
|
fNameReferenced = TRUE;
|
|||
|
|
|||
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (pClientCompletion)
|
|||
|
{
|
|||
|
(*pClientCompletion)(Context,STATUS_TIMEOUT);
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint(("DelayedNbtDeleteDevice: stopped name reg timer")) ;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|||
|
}
|
|||
|
|
|||
|
pEntry = pEntry->Flink;
|
|||
|
if (fNameReferenced)
|
|||
|
{
|
|||
|
fNameReferenced = FALSE;
|
|||
|
NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_DELETE_DEVICE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|||
|
|
|||
|
//
|
|||
|
// Walk through the AddressHead list. If any addresses exist and they
|
|||
|
// point to this device context, put the next device context. Also, update
|
|||
|
// adapter mask to reflect that this device context is now gone.
|
|||
|
//
|
|||
|
pLastAddress = NULL;
|
|||
|
pLastClient = NULL;
|
|||
|
pHead = pEntry = &NbtConfig.AddressHead;
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
|
|||
|
ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS);
|
|||
|
|
|||
|
//
|
|||
|
// Keep this Address around until we are done
|
|||
|
//
|
|||
|
NBT_REFERENCE_ADDRESS (pAddress, REF_ADDR_DEL_DEVICE);
|
|||
|
|
|||
|
//
|
|||
|
// If we had referenced a previous address, Deref it now!
|
|||
|
//
|
|||
|
if (pLastAddress)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
//
|
|||
|
// The last Client may need to have the address present
|
|||
|
// while dereferencing, so deref it if we need to!
|
|||
|
//
|
|||
|
if (pLastClient)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_CLIENT(pLastClient);
|
|||
|
pLastClient = NULL;
|
|||
|
}
|
|||
|
|
|||
|
NBT_DEREFERENCE_ADDRESS (pLastAddress, REF_ADDR_DEL_DEVICE);
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
pLastAddress = pAddress; // => Save this so that we can Deref it later
|
|||
|
|
|||
|
//
|
|||
|
// Need AddressLock to traverse ClientHead
|
|||
|
//
|
|||
|
CTESpinLock (pAddress, OldIrq2);
|
|||
|
|
|||
|
pClientEntry = &pAddress->ClientHead;
|
|||
|
while ((pClientEntry = pClientEntry->Flink) != &pAddress->ClientHead)
|
|||
|
{
|
|||
|
pClientEle = CONTAINING_RECORD (pClientEntry,tCLIENTELE,Linkage);
|
|||
|
|
|||
|
if (pClientEle->pDeviceContext == pDeviceContext)
|
|||
|
{
|
|||
|
CTESpinFree(pAddress, OldIrq2);
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
KdPrint(("Nbt.DelayedNbtDeleteDevice: Client:Context <%-16.16s:%x>:<%x>, EVReceive:EVContext=<%x:%x>\n\tFAILed to Cleanup on Device<%x>\n",
|
|||
|
pAddress->pNameAddr->Name, pAddress->pNameAddr->Name[15],
|
|||
|
pClientEle, pClientEle->evReceive, pClientEle->RcvEvContext, pDeviceContext));
|
|||
|
|
|||
|
if (pLastClient)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_CLIENT(pLastClient);
|
|||
|
}
|
|||
|
|
|||
|
pClientEle->pIrp = NULL;
|
|||
|
NbtCleanUpAddress(pClientEle,pDeviceContext);
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
CTESpinLock (pAddress, OldIrq2);
|
|||
|
pLastClient = pClientEle; // pClientEle still needs one more Deref
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
pAddress->pNameAddr->AdapterMask &= (~pDeviceContext->AdapterMask); // Clear Adapter Mask
|
|||
|
pAddress->pNameAddr->ConflictMask &= (~pDeviceContext->AdapterMask);
|
|||
|
|
|||
|
if ((!(pAddress->pNameAddr->AdapterMask)) &&
|
|||
|
(pAddress->pNameAddr->NameTypeState & STATE_CONFLICT))
|
|||
|
{
|
|||
|
pAddress->pNameAddr->NameTypeState &= (~NAME_STATE_MASK);
|
|||
|
pAddress->pNameAddr->NameTypeState |= STATE_RESOLVED;
|
|||
|
}
|
|||
|
CTESpinFree(pAddress, OldIrq2);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
//
|
|||
|
// If we had referenced a previous Client or Address, Deref it now!
|
|||
|
//
|
|||
|
if (pLastClient)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_CLIENT(pLastClient);
|
|||
|
}
|
|||
|
if (pLastAddress)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_ADDRESS (pLastAddress, REF_ADDR_DEL_DEVICE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if a call was started, but aborted then we could have some memory here!
|
|||
|
//
|
|||
|
while (!IsListEmpty(&pDeviceContext->UpConnectionInUse))
|
|||
|
{
|
|||
|
pEntry = RemoveHeadList(&pDeviceContext->UpConnectionInUse);
|
|||
|
pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
|
|||
|
NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CREATE);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
CTESpinLock(pDeviceContext,OldIrq1);
|
|||
|
//
|
|||
|
// We have finished our regular cleanup, so now close all the remaining TDI handles
|
|||
|
//
|
|||
|
while (!IsListEmpty(&pDeviceContext->LowerConnection))
|
|||
|
{
|
|||
|
pEntry = RemoveHeadList(&pDeviceContext->LowerConnection);
|
|||
|
InitializeListHead (pEntry);
|
|||
|
pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint (("Nbt.DelayedNbtDeleteDevice: Dereferencing pLowerConn <%x>\n", pLowerConn));
|
|||
|
NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, TRUE);
|
|||
|
}
|
|||
|
CTESpinFree(pDeviceContext,OldIrq1);
|
|||
|
|
|||
|
//
|
|||
|
// If this was the last Device to go away, stop the timers
|
|||
|
// (SmbDevice does not affect adapter count)
|
|||
|
//
|
|||
|
if (IsDeviceNetbiosless(pDeviceContext))
|
|||
|
{
|
|||
|
if (!(NbtConfig.AdapterCount))
|
|||
|
{
|
|||
|
//
|
|||
|
// No more devices funtioning, so stop the timers now!
|
|||
|
//
|
|||
|
fStopInitTimers = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (!(--NbtConfig.AdapterCount))
|
|||
|
{
|
|||
|
fStopInitTimers = TRUE;
|
|||
|
}
|
|||
|
else if (NbtConfig.AdapterCount == 1)
|
|||
|
{
|
|||
|
NbtConfig.MultiHomed = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (fStopInitTimers)
|
|||
|
{
|
|||
|
StopInitTimers();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now set the event for the waiting thread to complete!
|
|||
|
//
|
|||
|
KeSetEvent(&pDeviceContext->DeviceCleanedupEvent, 0, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
tDEVICECONTEXT *
|
|||
|
GetDeviceFromInterface(
|
|||
|
IN tIPADDRESS IpAddress,
|
|||
|
IN BOOLEAN fReferenceDevice
|
|||
|
)
|
|||
|
{
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pHead;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
ULONG IPInterfaceContext, Metric;
|
|||
|
tDEVICECONTEXT *pDeviceContext;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
if (IsListEmpty(&NbtConfig.DeviceContexts))
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink, tDEVICECONTEXT, Linkage);
|
|||
|
NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
pDeviceContext->pFastQuery(IpAddress, &IPInterfaceContext, &Metric);
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE);
|
|||
|
|
|||
|
pHead = pEntry = &NbtConfig.DeviceContexts;
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
pDeviceContext = CONTAINING_RECORD (pEntry,tDEVICECONTEXT,Linkage);
|
|||
|
if (pDeviceContext->IPInterfaceContext == IPInterfaceContext)
|
|||
|
{
|
|||
|
if (fReferenceDevice)
|
|||
|
{
|
|||
|
NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_OUT_FROM_IP, TRUE);
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
return pDeviceContext;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
tDEVICECONTEXT *
|
|||
|
GetAndRefNextDeviceFromNameAddr(
|
|||
|
IN tNAMEADDR *pNameAddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine finds the first adapter as specified in the name's adapter
|
|||
|
mask and set the DeviceContext associated with it. It then clears the
|
|||
|
bit in the adapter mask of pNameAddr.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
pDeviceContext if found a successful device!
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
CTEULONGLONG AdapterMask = 1;
|
|||
|
tDEVICECONTEXT *pDeviceContext = NULL;
|
|||
|
PLIST_ENTRY pHead;
|
|||
|
PLIST_ENTRY pEntry;
|
|||
|
|
|||
|
//
|
|||
|
// We may encounter an adapter for which the device is no
|
|||
|
// longer there, so we loop until we find the first valid
|
|||
|
// adapter or the mask is clear
|
|||
|
//
|
|||
|
while (pNameAddr->ReleaseMask)
|
|||
|
{
|
|||
|
//
|
|||
|
// Get the lowest AdapterMask bit and clear it in pNameAddr since
|
|||
|
// we are releasing the Name on that Adapter now
|
|||
|
//
|
|||
|
AdapterMask = ~(pNameAddr->ReleaseMask - 1) & pNameAddr->ReleaseMask;
|
|||
|
pNameAddr->ReleaseMask &= ~AdapterMask;
|
|||
|
|
|||
|
//
|
|||
|
// Get the DeviceContext for this adapter mask
|
|||
|
//
|
|||
|
pHead = &NbtConfig.DeviceContexts;
|
|||
|
pEntry = pHead->Flink;
|
|||
|
while (pEntry != pHead)
|
|||
|
{
|
|||
|
pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
|
|||
|
if (pDeviceContext->AdapterMask == AdapterMask)
|
|||
|
{
|
|||
|
//
|
|||
|
// Found a valid device on which this name is registered
|
|||
|
//
|
|||
|
#ifndef VXD
|
|||
|
NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_GET_REF, TRUE);
|
|||
|
#endif
|
|||
|
return pDeviceContext;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Go to next device
|
|||
|
//
|
|||
|
pEntry = pEntry->Flink;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
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 *) NbtAllocMem (sizeof(tCONTROLOBJECT), NBT_TAG2('21'));
|
|||
|
if (!pControl)
|
|||
|
{
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
pControl->Verify = NBT_VERIFY_CONTROL;
|
|||
|
|
|||
|
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);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DelayedNbtCloseFileHandles(
|
|||
|
IN tDGRAM_SEND_TRACKING *pUnused1,
|
|||
|
IN PVOID pContext,
|
|||
|
IN PVOID pUnused2,
|
|||
|
IN tDEVICECONTEXT *pUnused3
|
|||
|
)
|
|||
|
{
|
|||
|
BOOLEAN Attached = FALSE;
|
|||
|
NTSTATUS Status;
|
|||
|
tFILE_OBJECTS *pFileObjects = (tFILE_OBJECTS *) pContext;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
CTEAttachFsp(&Attached, REF_FSP_CLOSE_FILE_HANDLES);
|
|||
|
|
|||
|
if (pFileObjects->pNameServerFileObject)
|
|||
|
{
|
|||
|
ObDereferenceObject((PVOID *)pFileObjects->pNameServerFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tDelayedNbtCloseFileHandles->ObDereferenceObject\n",
|
|||
|
pFileObjects->pNameServerFileObject));
|
|||
|
|
|||
|
Status = ZwClose(pFileObjects->hNameServer);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tDelayedNbtCloseFileHandles->ZwClose, status = <%x>\n",
|
|||
|
pFileObjects->hNameServer, Status));
|
|||
|
NbtTrace(NBT_TRACE_PNP, ("%!FUNC! close NameServer UDP handle pFileObjects %p", pFileObjects));
|
|||
|
}
|
|||
|
|
|||
|
if (pFileObjects->pDgramFileObject)
|
|||
|
{
|
|||
|
ObDereferenceObject((PVOID *) pFileObjects->pDgramFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tDelayedNbtCloseFileHandles->ObDereferenceObject\n",
|
|||
|
pFileObjects->pDgramFileObject));
|
|||
|
|
|||
|
Status = ZwClose(pFileObjects->hDgram);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tDelayedNbtCloseFileHandles->ZwClose, status = <%x>\n",
|
|||
|
pFileObjects->hDgram, Status));
|
|||
|
NbtTrace(NBT_TRACE_PNP, ("%!FUNC! close Datagram UDP handle on pFileObjects %p", pFileObjects));
|
|||
|
}
|
|||
|
|
|||
|
CTEDetachFsp(Attached, REF_FSP_CLOSE_FILE_HANDLES);
|
|||
|
|
|||
|
CTEMemFree (pFileObjects);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
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;
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
PFILE_OBJECT pCFileObject;
|
|||
|
NTSTATUS Status;
|
|||
|
#endif // _PNP_POWER_
|
|||
|
tFILE_OBJECTS *pFileObjects = pDeviceContext->pFileObjects;
|
|||
|
|
|||
|
CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
|
|||
|
pDeviceContext->IpAddress = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Check for the existence of Objects under SpinLock and
|
|||
|
// then Close them outside of the SpinLock
|
|||
|
//
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (pSFileObject = pDeviceContext->pSessionFileObject)
|
|||
|
{
|
|||
|
pDeviceContext->pSessionFileObject = NULL;
|
|||
|
}
|
|||
|
|
|||
|
pDeviceContext->pFileObjects = NULL;
|
|||
|
if ((pFileObjects) &&
|
|||
|
(--pFileObjects->RefCount > 0))
|
|||
|
{
|
|||
|
NbtTrace(NBT_TRACE_PNP, ("%!FUNC! closing UDP handle on deivce %p will be delayed. (pFileObjects %p)",
|
|||
|
pDeviceContext, pFileObjects));
|
|||
|
pFileObjects = NULL;
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
CTEExReleaseResource(&NbtConfig.Resource);
|
|||
|
|
|||
|
//
|
|||
|
// Now close all the necessary objects as appropriate
|
|||
|
//
|
|||
|
CTEAttachFsp(&Attached, REF_FSP_CLOSE_ADDRESSES);
|
|||
|
if (pSFileObject)
|
|||
|
{
|
|||
|
ObDereferenceObject((PVOID *)pSFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tCloseAddressesWithTransport2->ObDereferenceObject\n", pSFileObject));
|
|||
|
Status = ZwClose(pDeviceContext->hSession);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tCloseAddressesWithTransport2->ZwClose, status = <%x>\n", pDeviceContext->hSession, Status));
|
|||
|
pDeviceContext->hSession = NULL;
|
|||
|
NbtTrace(NBT_TRACE_PNP, ("%!FUNC! close TCP session handle on device %p", pDeviceContext));
|
|||
|
}
|
|||
|
|
|||
|
if (pFileObjects)
|
|||
|
{
|
|||
|
DelayedNbtCloseFileHandles (NULL, pFileObjects, NULL, NULL);
|
|||
|
}
|
|||
|
|
|||
|
CTEDetachFsp(Attached, REF_FSP_CLOSE_ADDRESSES);
|
|||
|
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, locstatus;
|
|||
|
ULONG ValueMask;
|
|||
|
UCHAR IpAddrByte;
|
|||
|
tFILE_OBJECTS *pFileObjects;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
if (!(pFileObjects = (tFILE_OBJECTS *) NbtAllocMem (sizeof(tFILE_OBJECTS), NBT_TAG2('39'))))
|
|||
|
{
|
|||
|
KdPrint(("Nbt.NbtCreateAddressObjects: Failed to allocate memory for FileObject context!\n"));
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
CTEZeroMemory(pFileObjects, sizeof(tFILE_OBJECTS));
|
|||
|
pFileObjects->RefCount = 1;
|
|||
|
|
|||
|
//
|
|||
|
// 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 = NbtConfig.RegistryBcastAddr;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pDeviceContext->BroadcastAddress = ValueMask;
|
|||
|
}
|
|||
|
|
|||
|
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 (&pFileObjects->hDgram,
|
|||
|
&pFileObjects->pDgramDeviceObject,
|
|||
|
&pFileObjects->pDgramFileObject,
|
|||
|
pDeviceContext,
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
pDeviceContext->DatagramPort,
|
|||
|
#else
|
|||
|
(USHORT)NBT_DATAGRAM_UDP_PORT,
|
|||
|
#endif
|
|||
|
pDeviceContext->IpAddress,
|
|||
|
0); // not a TCP port
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
if (pDeviceContext->NameServerPort == 0)
|
|||
|
{
|
|||
|
pFileObjects->hNameServer = NULL;
|
|||
|
pFileObjects->pNameServerDeviceObject = NULL;
|
|||
|
pFileObjects->pNameServerFileObject = NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
#endif
|
|||
|
{
|
|||
|
// open the Nameservice UDP port ..
|
|||
|
status = NbtTdiOpenAddress (&pFileObjects->hNameServer,
|
|||
|
&pFileObjects->pNameServerDeviceObject,
|
|||
|
&pFileObjects->pNameServerFileObject,
|
|||
|
pDeviceContext,
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
pDeviceContext->NameServerPort,
|
|||
|
#else
|
|||
|
(USHORT)NBT_NAMESERVICE_UDP_PORT,
|
|||
|
#endif
|
|||
|
pDeviceContext->IpAddress,
|
|||
|
0); // not a TCP port
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint(("Nbt.NbtCreateAddressObjects: Open Session Port=<%d>, pDeviceContext=<%x>\n",
|
|||
|
pDeviceContext->SessionPort, pDeviceContext));
|
|||
|
#endif
|
|||
|
|
|||
|
// Open the TCP port for Session Services
|
|||
|
status = NbtTdiOpenAddress (&pDeviceContext->hSession,
|
|||
|
&pDeviceContext->pSessionDeviceObject,
|
|||
|
&pDeviceContext->pSessionFileObject,
|
|||
|
pDeviceContext,
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
pDeviceContext->SessionPort,
|
|||
|
#else
|
|||
|
(USHORT)NBT_SESSION_TCP_PORT,
|
|||
|
#endif
|
|||
|
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);
|
|||
|
|
|||
|
//
|
|||
|
// If this is P-to-P, and the Subnet mask is all 1's, set broadcast
|
|||
|
// address to all 1's and limit broadcast to this interface only
|
|||
|
//
|
|||
|
if ((pDeviceContext->IpInterfaceFlags & (IP_INTFC_FLAG_P2P | IP_INTFC_FLAG_P2MP)) &&
|
|||
|
(SubnetMask == DEFAULT_BCAST_ADDR)) // If SubnetMask == -1 and connection is P-to-P
|
|||
|
{
|
|||
|
pDeviceContext->BroadcastAddress = DEFAULT_BCAST_ADDR;
|
|||
|
|
|||
|
if (pFileObjects->hNameServer)
|
|||
|
{
|
|||
|
NbtSetTcpInfo (pFileObjects->hNameServer,
|
|||
|
AO_OPTION_LIMIT_BCASTS,
|
|||
|
INFO_TYPE_ADDRESS_OBJECT,
|
|||
|
(ULONG)TRUE);
|
|||
|
}
|
|||
|
|
|||
|
if (pFileObjects->hDgram)
|
|||
|
{
|
|||
|
NbtSetTcpInfo (pFileObjects->hDgram,
|
|||
|
AO_OPTION_LIMIT_BCASTS,
|
|||
|
INFO_TYPE_ADDRESS_OBJECT,
|
|||
|
(ULONG)TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (!pDeviceContext->pFileObjects);
|
|||
|
pDeviceContext->pFileObjects = pFileObjects;
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint(("Nbt.NbtCreateAddressObjects: Error opening Session address with TDI, status=<%x>\n",status));
|
|||
|
|
|||
|
//
|
|||
|
// Ensure that the Object pointers are NULLed out!
|
|||
|
//
|
|||
|
pDeviceContext->pSessionFileObject = NULL;
|
|||
|
|
|||
|
ObDereferenceObject(pFileObjects->pNameServerFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tNbtCreateAddressObjects1->ObDereferenceObject\n", pFileObjects->pNameServerFileObject));
|
|||
|
pFileObjects->pNameServerFileObject = NULL;
|
|||
|
|
|||
|
locstatus = NTZwCloseFile(pFileObjects->hNameServer);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tNbtCreateAddressObjects1->NTZwCloseFile (NameServer), status = <%x>\n", pFileObjects->hNameServer, locstatus));
|
|||
|
}
|
|||
|
ObDereferenceObject(pFileObjects->pDgramFileObject);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t --< ><====<%x>\tNbtCreateAddressObjects2->ObDereferenceObject\n", pFileObjects->pDgramFileObject));
|
|||
|
pFileObjects->pDgramFileObject = NULL;
|
|||
|
|
|||
|
locstatus = NTZwCloseFile(pFileObjects->hDgram);
|
|||
|
IF_DBG(NBT_DEBUG_HANDLES)
|
|||
|
KdPrint (("\t<===<%x>\tNbtCreateAddressObjects2->NTZwCloseFile (Dgram), status = <%x>\n", pFileObjects->hDgram, locstatus));
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_NTUTIL)
|
|||
|
KdPrint(("Unable to Open NameServer port with TDI, status = %X\n",status));
|
|||
|
}
|
|||
|
|
|||
|
CTEMemFree (pFileObjects);
|
|||
|
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;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
HANDLE event;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
NTSTATUS Status;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
HANDLE hTcp;
|
|||
|
ULONG Length;
|
|||
|
UCHAR pBuffer[256];
|
|||
|
ULONG BufferSize = 256;
|
|||
|
BOOLEAN Attached = FALSE;
|
|||
|
PWSTR pName = L"Tcp";
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef HDL_FIX
|
|||
|
InitializeObjectAttributes (&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, NULL, NULL);
|
|||
|
#else
|
|||
|
InitializeObjectAttributes (&ObjectAttributes, &DeviceName, 0, NULL, NULL);
|
|||
|
#endif // HDL_FIX
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_TDIADDR)
|
|||
|
KdPrint(("Nbt.GetExtendedAttributes: 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))
|
|||
|
{
|
|||
|
ZwClose( hTcp );
|
|||
|
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 = NtWaitForSingleObject (event, FALSE, NULL);
|
|||
|
ASSERT(status == STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
pDeviceContext->IpInterfaceFlags = ((IPInterfaceInfo *) pBuffer)->iii_flags;
|
|||
|
|
|||
|
//
|
|||
|
// 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));
|
|||
|
|
|||
|
//
|
|||
|
// 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));
|
|||
|
|
|||
|
status = IoStatus.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;
|
|||
|
|
|||
|
*ppMdl = NULL;
|
|||
|
if (NbtConfig.iCurrentNumBuff[eBuffType] >= NbtConfig.iMaxNumBuff[eBuffType])
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
lBufferSize = NbtConfig.iBufferSize[eBuffType];
|
|||
|
|
|||
|
pBuffer = NbtAllocMem((USHORT)lBufferSize,NBT_TAG('g'));
|
|||
|
if (!pBuffer)
|
|||
|
{
|
|||
|
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);
|
|||
|
|
|||
|
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]++;
|
|||
|
*ppMdl = pMdl;
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
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.
|
|||
|
//
|
|||
|
CTEAttachFsp(&Attached, REF_FSP_CLOSE_FILE);
|
|||
|
status = ZwClose(Handle);
|
|||
|
CTEDetachFsp(Attached, REF_FSP_CLOSE_FILE);
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
tADDRARRAY DeviceAddressArray;
|
|||
|
PLIST_ENTRY pHead;
|
|||
|
PLIST_ENTRY pEntry;
|
|||
|
#ifdef MULTIPLE_WINS
|
|||
|
int j;
|
|||
|
#endif
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
|
|||
|
ASSERT (NBT_VERIFY_HANDLE2 (pDeviceContext, NBT_VERIFY_DEVCONTEXT, NBT_VERIFY_DEVCONTEXT_DOWN));
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_NAMESRV)
|
|||
|
KdPrint(("NBT:Found BindName: %lx\n", pDeviceContext->BindName));
|
|||
|
|
|||
|
|
|||
|
if (LookupDeviceInRegistry(&pDeviceContext->BindName, &DeviceAddressArray, NULL) == STATUS_SUCCESS) {
|
|||
|
//
|
|||
|
// We found a match
|
|||
|
//
|
|||
|
pDeviceContext->lNameServerAddress = DeviceAddressArray.NameServerAddress;
|
|||
|
pDeviceContext->lBackupServer = DeviceAddressArray.BackupServer;
|
|||
|
pDeviceContext->SwitchedToBackup = 0;
|
|||
|
pDeviceContext->RefreshToBackup = 0;
|
|||
|
#ifdef MULTIPLE_WINS
|
|||
|
pDeviceContext->lNumOtherServers = DeviceAddressArray.NumOtherServers;
|
|||
|
pDeviceContext->lLastResponsive = 0;
|
|||
|
for (j = 0; j < DeviceAddressArray.NumOtherServers; j++) {
|
|||
|
pDeviceContext->lOtherServers[j] = DeviceAddressArray.Others[j];
|
|||
|
}
|
|||
|
#endif
|
|||
|
#ifdef _NETBIOSLESS
|
|||
|
pDeviceContext->NetbiosEnabled = DeviceAddressArray.NetbiosEnabled;
|
|||
|
IF_DBG(NBT_DEBUG_NAMESRV)
|
|||
|
KdPrint(("Nbt.NTReReadRegistry: <%wZ> NetbiosEnabled=<%d>\n",
|
|||
|
&pDeviceContext->ExportName, pDeviceContext->NetbiosEnabled));
|
|||
|
#endif
|
|||
|
pDeviceContext->RasProxyFlags = DeviceAddressArray.RasProxyFlags;
|
|||
|
pDeviceContext->EnableNagling = DeviceAddressArray.EnableNagling;
|
|||
|
SetNodeType();
|
|||
|
} else {
|
|||
|
KdPrint(("netbt!NtReReadRegistry: Cannot find device in the registry\n"));
|
|||
|
}
|
|||
|
|
|||
|
if (pDeviceContext->IpAddress)
|
|||
|
{
|
|||
|
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(pDeviceContext, FALSE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// no need to refresh
|
|||
|
// on a Bnode
|
|||
|
//
|
|||
|
NbtStopRefreshTimer();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
ULONG EventLogSequenceNumber = 0;
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbtLogEventDetailed(
|
|||
|
IN ULONG EventCode,
|
|||
|
IN NTSTATUS NtStatusCode,
|
|||
|
IN ULONG Info,
|
|||
|
IN PVOID RawDataBuffer,
|
|||
|
IN USHORT RawDataLength,
|
|||
|
IN USHORT NumberOfInsertionStrings,
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
#define LAST_NAMED_ARGUMENT NumberOfInsertionStrings
|
|||
|
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function allocates an I/O error log record, fills it in and writes it
|
|||
|
to the I/O error log.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIO_ERROR_LOG_PACKET ErrorLogEntry;
|
|||
|
va_list ParmPtr; // Pointer to stack parms.
|
|||
|
PCHAR DumpData;
|
|||
|
LONG Length;
|
|||
|
ULONG i, SizeOfRawData, RemainingSpace, TotalErrorLogEntryLength;
|
|||
|
ULONG SizeOfStringData = 0;
|
|||
|
PWSTR StringOffset, InsertionString;
|
|||
|
|
|||
|
if (NumberOfInsertionStrings != 0)
|
|||
|
{
|
|||
|
va_start (ParmPtr, LAST_NAMED_ARGUMENT);
|
|||
|
|
|||
|
for (i = 0; i < NumberOfInsertionStrings; i += 1)
|
|||
|
{
|
|||
|
InsertionString = va_arg (ParmPtr, PWSTR);
|
|||
|
Length = wcslen (InsertionString);
|
|||
|
while ((Length > 0) && (InsertionString[Length-1] == L' '))
|
|||
|
{
|
|||
|
Length--;
|
|||
|
}
|
|||
|
|
|||
|
SizeOfStringData += (Length + 1) * sizeof(WCHAR);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ideally we want the packet to hold the servername and ExtraInformation.
|
|||
|
// Usually the ExtraInformation gets truncated.
|
|||
|
//
|
|||
|
TotalErrorLogEntryLength = min (RawDataLength + sizeof(IO_ERROR_LOG_PACKET) + 1 + SizeOfStringData,
|
|||
|
ERROR_LOG_MAXIMUM_SIZE);
|
|||
|
|
|||
|
RemainingSpace = TotalErrorLogEntryLength - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData);
|
|||
|
if (RemainingSpace > SizeOfStringData)
|
|||
|
{
|
|||
|
SizeOfRawData = RemainingSpace - SizeOfStringData;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SizeOfStringData = RemainingSpace;
|
|||
|
SizeOfRawData = 0;
|
|||
|
}
|
|||
|
|
|||
|
ErrorLogEntry = IoAllocateErrorLogEntry (NbtConfig.DriverObject, (UCHAR) TotalErrorLogEntryLength);
|
|||
|
if (ErrorLogEntry == NULL)
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_NAMESRV)
|
|||
|
KdPrint(("Nbt: Unable to allocate Error Packet for Error logging\n"));
|
|||
|
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the error log entry
|
|||
|
//
|
|||
|
ErrorLogEntry->ErrorCode = EventCode;
|
|||
|
ErrorLogEntry->UniqueErrorValue = Info;
|
|||
|
ErrorLogEntry->FinalStatus = NtStatusCode;
|
|||
|
ErrorLogEntry->MajorFunctionCode = 0;
|
|||
|
ErrorLogEntry->RetryCount = 0;
|
|||
|
ErrorLogEntry->IoControlCode = 0;
|
|||
|
ErrorLogEntry->DeviceOffset.LowPart = 0;
|
|||
|
ErrorLogEntry->DeviceOffset.HighPart = 0;
|
|||
|
ErrorLogEntry->DumpDataSize = 0;
|
|||
|
ErrorLogEntry->NumberOfStrings = 0;
|
|||
|
ErrorLogEntry->SequenceNumber = EventLogSequenceNumber++;
|
|||
|
ErrorLogEntry->StringOffset = (USHORT) (ROUND_UP_COUNT (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)
|
|||
|
+ SizeOfRawData, ALIGN_WORD));
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Append the dump data. This information is typically an SMB header.
|
|||
|
//
|
|||
|
if ((RawDataBuffer) && (SizeOfRawData))
|
|||
|
{
|
|||
|
DumpData = (PCHAR) ErrorLogEntry->DumpData;
|
|||
|
Length = min (RawDataLength, (USHORT)SizeOfRawData);
|
|||
|
RtlCopyMemory (DumpData, RawDataBuffer, Length);
|
|||
|
ErrorLogEntry->DumpDataSize = (USHORT)Length;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add the debug informatuion strings
|
|||
|
//
|
|||
|
if (NumberOfInsertionStrings)
|
|||
|
{
|
|||
|
StringOffset = (PWSTR) ((PCHAR)ErrorLogEntry + ErrorLogEntry->StringOffset);
|
|||
|
|
|||
|
//
|
|||
|
// Set up ParmPtr to point to first of the caller's parameters.
|
|||
|
//
|
|||
|
va_start(ParmPtr, LAST_NAMED_ARGUMENT);
|
|||
|
|
|||
|
for (i = 0 ; i < NumberOfInsertionStrings ; i+= 1)
|
|||
|
{
|
|||
|
InsertionString = va_arg(ParmPtr, PWSTR);
|
|||
|
Length = wcslen(InsertionString);
|
|||
|
while ( (Length > 0) && (InsertionString[Length-1] == L' '))
|
|||
|
{
|
|||
|
Length--;
|
|||
|
}
|
|||
|
|
|||
|
if (((Length + 1) * sizeof(WCHAR)) > SizeOfStringData)
|
|||
|
{
|
|||
|
Length = (SizeOfStringData/sizeof(WCHAR)) - 1;
|
|||
|
}
|
|||
|
|
|||
|
if (Length > 0)
|
|||
|
{
|
|||
|
RtlCopyMemory (StringOffset, InsertionString, Length*sizeof(WCHAR));
|
|||
|
StringOffset += Length;
|
|||
|
*StringOffset++ = L'\0';
|
|||
|
|
|||
|
SizeOfStringData -= (Length + 1) * sizeof(WCHAR);
|
|||
|
|
|||
|
ErrorLogEntry->NumberOfStrings += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IoWriteErrorLogEntry(ErrorLogEntry);
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbtLogEvent(
|
|||
|
IN ULONG EventCode,
|
|||
|
IN NTSTATUS Status,
|
|||
|
IN ULONG Location
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return (NbtLogEventDetailed (EventCode, Status, Location, NULL, 0, 0));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DelayedNbtLogDuplicateNameEvent(
|
|||
|
IN PVOID Context1,
|
|||
|
IN PVOID Context2,
|
|||
|
IN PVOID Context3,
|
|||
|
IN tDEVICECONTEXT *pDeviceContext
|
|||
|
)
|
|||
|
{
|
|||
|
tNAMEADDR *pNameAddr = (tNAMEADDR *) Context1;
|
|||
|
tIPADDRESS RemoteIpAddress = (tIPADDRESS) PtrToUlong (Context2);
|
|||
|
ULONG Location = (ULONG) PtrToUlong (Context3);
|
|||
|
UCHAR *pszNameOrig = pNameAddr->Name;
|
|||
|
|
|||
|
NTSTATUS status;
|
|||
|
UCHAR *pAddr;
|
|||
|
WCHAR wstrName[22];
|
|||
|
WCHAR wstrDeviceIp[22];
|
|||
|
WCHAR wstrRemoteServerIp[22];
|
|||
|
|
|||
|
UCHAR pszName[22];
|
|||
|
STRING TmpOEMString;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
UnicodeString.MaximumLength = sizeof(WCHAR)*(22);
|
|||
|
|
|||
|
sprintf (pszName,"%-15.15s:%x", pszNameOrig, pszNameOrig[15]);
|
|||
|
UnicodeString.Length = 0;
|
|||
|
UnicodeString.Buffer = wstrName;
|
|||
|
RtlInitString (&TmpOEMString, pszName);
|
|||
|
status = RtlOemStringToUnicodeString (&UnicodeString, &TmpOEMString, FALSE);
|
|||
|
UnicodeString.Buffer[UnicodeString.Length] = L'\0';
|
|||
|
|
|||
|
pAddr = (PUCHAR) &pDeviceContext->IpAddress;
|
|||
|
swprintf (wstrDeviceIp, L"%d.%d.%d.%d", pAddr[3], pAddr[2], pAddr[1], pAddr[0]);
|
|||
|
|
|||
|
pAddr = (PUCHAR) &RemoteIpAddress;
|
|||
|
swprintf (wstrRemoteServerIp, L"%d.%d.%d.%d", pAddr[3], pAddr[2], pAddr[1], pAddr[0]);
|
|||
|
|
|||
|
status = NbtLogEventDetailed (EVENT_NBT_DUPLICATE_NAME_ERROR,
|
|||
|
STATUS_UNSUCCESSFUL,
|
|||
|
Location,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
3,
|
|||
|
&wstrName,
|
|||
|
&wstrDeviceIp,
|
|||
|
&wstrRemoteServerIp);
|
|||
|
|
|||
|
NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if DBG
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
AcquireSpinLockDebug(
|
|||
|
IN tNBT_LOCK_INFO *pLockInfo,
|
|||
|
IN PKIRQL pOldIrq,
|
|||
|
IN INT LineNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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(&pLockInfo->SpinLock,pOldIrq);
|
|||
|
|
|||
|
CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
|
|||
|
NbtConfig.CurrProc = CurrProc;
|
|||
|
|
|||
|
LockFree = (pLockInfo->LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]);
|
|||
|
if (!LockFree)
|
|||
|
{
|
|||
|
KdPrint(("Nbt.AcquireSpinLockDebug: CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n",
|
|||
|
CurrProc,NbtConfig.CurrentLockNumber[CurrProc],pLockInfo->LockNumber));
|
|||
|
} \
|
|||
|
|
|||
|
ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree);
|
|||
|
NbtConfig.CurrentLockNumber[CurrProc]|= pLockInfo->LockNumber;
|
|||
|
|
|||
|
pLockInfo->LastLockLine = LineNumber;
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
FreeSpinLockDebug(
|
|||
|
IN tNBT_LOCK_INFO *pLockInfo,
|
|||
|
IN KIRQL OldIrq,
|
|||
|
IN INT LineNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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] &= ~pLockInfo->LockNumber;
|
|||
|
|
|||
|
pLockInfo->LastReleaseLine = LineNumber;
|
|||
|
CTEFreeLock(&pLockInfo->SpinLock,OldIrq);
|
|||
|
}
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
AcquireSpinLockAtDpcDebug(
|
|||
|
IN tNBT_LOCK_INFO *pLockInfo,
|
|||
|
IN INT LineNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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(&pLockInfo->SpinLock, 0);
|
|||
|
pLockInfo->LastLockLine = LineNumber;
|
|||
|
|
|||
|
CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
|
|||
|
NbtConfig.CurrProc = CurrProc;
|
|||
|
|
|||
|
LockFree = (pLockInfo->LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]);
|
|||
|
if (!LockFree)
|
|||
|
{
|
|||
|
KdPrint(("Nbt.AcquireSpinLockAtDpcDebug: CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n",
|
|||
|
CurrProc,NbtConfig.CurrentLockNumber[CurrProc],pLockInfo->LockNumber));
|
|||
|
} \
|
|||
|
|
|||
|
ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree);
|
|||
|
NbtConfig.CurrentLockNumber[CurrProc]|= pLockInfo->LockNumber;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
FreeSpinLockAtDpcDebug(
|
|||
|
IN tNBT_LOCK_INFO *pLockInfo,
|
|||
|
IN INT LineNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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] &= ~pLockInfo->LockNumber;
|
|||
|
|
|||
|
pLockInfo->LastReleaseLine = LineNumber;
|
|||
|
CTEFreeLockFromDPC(&pLockInfo->SpinLock, 0);
|
|||
|
}
|
|||
|
#endif //if Dbg
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbtBuildDeviceAcl(
|
|||
|
OUT PACL * DeviceAcl
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
(Lifted from TCP - TcpBuildDeviceAcl)
|
|||
|
This routine builds an ACL which gives Administrators, LocalService and NetworkService
|
|||
|
principals full access. All other principals have no access.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceAcl - Output pointer to the new ACL.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS or an appropriate error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PGENERIC_MAPPING GenericMapping;
|
|||
|
PSID AdminsSid, ServiceSid, NetworkSid;
|
|||
|
ULONG AclLength;
|
|||
|
NTSTATUS Status;
|
|||
|
ACCESS_MASK AccessMask = GENERIC_ALL;
|
|||
|
PACL NewAcl;
|
|||
|
|
|||
|
//
|
|||
|
// Enable access to all the globally defined SIDs
|
|||
|
//
|
|||
|
|
|||
|
GenericMapping = IoGetFileObjectGenericMapping();
|
|||
|
|
|||
|
RtlMapGenericMask(&AccessMask, GenericMapping);
|
|||
|
|
|||
|
AdminsSid = SeExports->SeAliasAdminsSid;
|
|||
|
ServiceSid = SeExports->SeLocalServiceSid;
|
|||
|
NetworkSid = SeExports->SeNetworkServiceSid;
|
|||
|
|
|||
|
AclLength = sizeof(ACL) +
|
|||
|
3 * sizeof(ACCESS_ALLOWED_ACE) +
|
|||
|
RtlLengthSid(AdminsSid) +
|
|||
|
RtlLengthSid(ServiceSid) +
|
|||
|
RtlLengthSid(NetworkSid) -
|
|||
|
3 * sizeof(ULONG);
|
|||
|
|
|||
|
NewAcl = ExAllocatePool(PagedPool, AclLength);
|
|||
|
|
|||
|
if (NewAcl == NULL) {
|
|||
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ExFreePool(NewAcl);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
Status = RtlAddAccessAllowedAce(
|
|||
|
NewAcl,
|
|||
|
ACL_REVISION2,
|
|||
|
AccessMask,
|
|||
|
AdminsSid
|
|||
|
);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ExFreePool(NewAcl);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlAddAccessAllowedAce(
|
|||
|
NewAcl,
|
|||
|
ACL_REVISION2,
|
|||
|
AccessMask,
|
|||
|
ServiceSid
|
|||
|
);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ExFreePool(NewAcl);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
Status = RtlAddAccessAllowedAce(
|
|||
|
NewAcl,
|
|||
|
ACL_REVISION2,
|
|||
|
AccessMask,
|
|||
|
NetworkSid
|
|||
|
);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ExFreePool(NewAcl);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
*DeviceAcl = NewAcl;
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbtCreateAdminSecurityDescriptor(PDEVICE_OBJECT dev)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
(Lifted from TCP - TcpCreateAdminSecurityDescriptor)
|
|||
|
This routine creates a security descriptor which gives access
|
|||
|
only to Administrtors and LocalService. This descriptor is used
|
|||
|
to access check raw endpoint opens and exclisive access to transport
|
|||
|
addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS or an appropriate error code.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PACL rawAcl = NULL;
|
|||
|
NTSTATUS status;
|
|||
|
CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|||
|
PSECURITY_DESCRIPTOR localSecurityDescriptor = (PSECURITY_DESCRIPTOR) & buffer;
|
|||
|
SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
|
|||
|
|
|||
|
//
|
|||
|
// Build a local security descriptor with an ACL giving only
|
|||
|
// administrators and service access.
|
|||
|
//
|
|||
|
status = NbtBuildDeviceAcl(&rawAcl);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
KdPrint(("TCP: Unable to create Raw ACL, error: %x\n", status));
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
(VOID) RtlCreateSecurityDescriptor(
|
|||
|
localSecurityDescriptor,
|
|||
|
SECURITY_DESCRIPTOR_REVISION
|
|||
|
);
|
|||
|
|
|||
|
(VOID) RtlSetDaclSecurityDescriptor(
|
|||
|
localSecurityDescriptor,
|
|||
|
TRUE,
|
|||
|
rawAcl,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Now apply the local descriptor to the raw descriptor.
|
|||
|
//
|
|||
|
status = SeSetSecurityDescriptorInfo(
|
|||
|
NULL,
|
|||
|
&securityInformation,
|
|||
|
localSecurityDescriptor,
|
|||
|
&dev->SecurityDescriptor,
|
|||
|
PagedPool,
|
|||
|
IoGetFileObjectGenericMapping()
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
KdPrint(("Nbt: SeSetSecurity failed, %lx\n", status));
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(rawAcl);
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|