840 lines
25 KiB
C
840 lines
25 KiB
C
|
//
|
|||
|
//
|
|||
|
// hashtbl.c
|
|||
|
//
|
|||
|
// This file contains the name code to implement the local and remote
|
|||
|
// hash tables used to store local and remote names to IP addresses
|
|||
|
// The hash table should not use more than 256 buckets since the hash
|
|||
|
// index is only calculated to one byte!
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
|
|||
|
|
|||
|
VOID DestroyHashTable(IN PHASHTABLE pHashTable);
|
|||
|
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma CTEMakePageable(INIT, CreateHashTable)
|
|||
|
#pragma CTEMakePageable(PAGE, DestroyHashTables)
|
|||
|
#pragma CTEMakePageable(PAGE, DestroyHashTable)
|
|||
|
#endif
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
CreateHashTable(
|
|||
|
tHASHTABLE **pHashTable,
|
|||
|
LONG lNumBuckets,
|
|||
|
enum eNbtLocation LocalRemote
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates a hash table uTableSize long.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG uSize;
|
|||
|
LONG i;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
uSize = (lNumBuckets-1)*sizeof(LIST_ENTRY) + sizeof(tHASHTABLE);
|
|||
|
|
|||
|
*pHashTable = (tHASHTABLE *) NbtAllocMem (uSize, NBT_TAG2('01'));
|
|||
|
|
|||
|
if (*pHashTable)
|
|||
|
{
|
|||
|
// initialize all of the buckets to have null chains off of them
|
|||
|
for (i=0;i < lNumBuckets ;i++ )
|
|||
|
{
|
|||
|
InitializeListHead(&(*pHashTable)->Bucket[i]);
|
|||
|
}
|
|||
|
|
|||
|
(*pHashTable)->LocalRemote = LocalRemote;
|
|||
|
(*pHashTable)->lNumBuckets = lNumBuckets;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_HASHTBL)
|
|||
|
KdPrint(("Nbt.CreateHashTable: Unable to create hash table\n"));
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
VOID
|
|||
|
DestroyHashTable(
|
|||
|
IN PHASHTABLE pHashTable
|
|||
|
)
|
|||
|
{
|
|||
|
LONG i, j;
|
|||
|
tNAMEADDR *pNameAddr;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
|
|||
|
if (pHashTable == NULL) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Go through all the buckets to see if there are any names left
|
|||
|
*/
|
|||
|
for (i = 0; i < pHashTable->lNumBuckets; i++) {
|
|||
|
while (!IsListEmpty(&(pHashTable->Bucket[i]))) {
|
|||
|
pEntry = RemoveHeadList(&(pHashTable->Bucket[i]));
|
|||
|
pNameAddr = CONTAINING_RECORD(pEntry, tNAMEADDR, Linkage);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_HASHTBL)
|
|||
|
KdPrint (("netbt!DestroyHashTable: WARNING! Freeing Name: <%16.16s:%x>\n",
|
|||
|
pNameAddr->Name, pNameAddr->Name[15]));
|
|||
|
|
|||
|
/*
|
|||
|
* Notify deferencer not to do RemoveListEntry again becaseu we already do it above.
|
|||
|
*/
|
|||
|
if (pNameAddr->Verify == REMOTE_NAME && (pNameAddr->NameTypeState & PRELOADED)) {
|
|||
|
ASSERT(pNameAddr->RefCount == 2);
|
|||
|
NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_PRELOADED, FALSE);
|
|||
|
}
|
|||
|
ASSERT(pNameAddr->RefCount == 1);
|
|||
|
pNameAddr->Linkage.Flink = pNameAddr->Linkage.Blink = NULL;
|
|||
|
NBT_DEREFERENCE_NAMEADDR(pNameAddr,((pNameAddr->Verify==LOCAL_NAME)?REF_NAME_LOCAL:REF_NAME_REMOTE),FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
CTEMemFree(pHashTable);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
DestroyHashTables(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine destroys a hash table and frees the entries in NumBuckets
|
|||
|
It Must be called with the NbtConfig lock held!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
CTEPagedCode();
|
|||
|
IF_DBG(NBT_DEBUG_HASHTBL)
|
|||
|
KdPrint (("netbt!DestroyHashTables: destroying remote hash table ..."));
|
|||
|
DestroyHashTable(NbtConfig.pRemoteHashTbl);
|
|||
|
NbtConfig.pRemoteHashTbl = NULL;
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_HASHTBL)
|
|||
|
KdPrint (("\nnetbt!DestroyHashTables: destroying local hash table ..."));
|
|||
|
DestroyHashTable(NbtConfig.pLocalHashTbl);
|
|||
|
NbtConfig.pLocalHashTbl = NULL;
|
|||
|
IF_DBG(NBT_DEBUG_HASHTBL)
|
|||
|
KdPrint (("\n"));
|
|||
|
}
|
|||
|
#endif // _PNP_POWER_
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NbtUpdateRemoteName(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN tNAMEADDR *pNameAddrNew,
|
|||
|
IN tNAMEADDR *pNameAddrDiscard,
|
|||
|
IN USHORT NameAddFlags
|
|||
|
)
|
|||
|
{
|
|||
|
tIPADDRESS IpAddress;
|
|||
|
tIPADDRESS *pLmhSvcGroupList = NULL;
|
|||
|
tIPADDRESS *pOrigIpAddrs = NULL;
|
|||
|
ULONG AdapterIndex = 0; // by default
|
|||
|
ULONG i;
|
|||
|
|
|||
|
ASSERT (pNameAddrNew);
|
|||
|
//
|
|||
|
// See if we need to grow the IP addrs cache for the cached name
|
|||
|
//
|
|||
|
if (pNameAddrNew->RemoteCacheLen < NbtConfig.RemoteCacheLen) {
|
|||
|
tADDRESS_ENTRY *pRemoteCache;
|
|||
|
pRemoteCache = (tADDRESS_ENTRY *)NbtAllocMem(NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY),NBT_TAG2('02'));
|
|||
|
if (pRemoteCache) {
|
|||
|
CTEZeroMemory(pRemoteCache, NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY));
|
|||
|
|
|||
|
/*
|
|||
|
* Copy data from and free the previous cache (if any)
|
|||
|
*/
|
|||
|
if (pNameAddrNew->pRemoteIpAddrs) {
|
|||
|
CTEMemCopy (pRemoteCache, pNameAddrNew->pRemoteIpAddrs,
|
|||
|
sizeof(tADDRESS_ENTRY) * pNameAddrNew->RemoteCacheLen);
|
|||
|
|
|||
|
CTEFreeMem (pNameAddrNew->pRemoteIpAddrs)
|
|||
|
}
|
|||
|
|
|||
|
pNameAddrNew->pRemoteIpAddrs = pRemoteCache;
|
|||
|
pNameAddrNew->RemoteCacheLen = NbtConfig.RemoteCacheLen;
|
|||
|
} else {
|
|||
|
KdPrint(("Nbt.NbtUpdateRemoteName: FAILed to expand Cache entry!\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the new entry being added replaces an entry which was
|
|||
|
// either pre-loaded or set by a client, and the new entry itself
|
|||
|
// does not have that flag set, then ignore this update.
|
|||
|
//
|
|||
|
ASSERT (NAME_RESOLVED_BY_DNS > NAME_RESOLVED_BY_LMH_P); // For the check below to succeed!
|
|||
|
|
|||
|
if (((pNameAddrNew->NameAddFlags & NAME_RESOLVED_BY_CLIENT) !=
|
|||
|
(NameAddFlags & NAME_RESOLVED_BY_CLIENT)) ||
|
|||
|
((pNameAddrNew->NameAddFlags & NAME_RESOLVED_BY_LMH_P) >
|
|||
|
(NameAddFlags & (NAME_RESOLVED_BY_LMH_P | NAME_RESOLVED_BY_DNS))))
|
|||
|
{
|
|||
|
return (STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
if (pNameAddrDiscard)
|
|||
|
{
|
|||
|
IpAddress = pNameAddrDiscard->IpAddress;
|
|||
|
pLmhSvcGroupList = pNameAddrDiscard->pLmhSvcGroupList;
|
|||
|
pNameAddrDiscard->pLmhSvcGroupList = NULL;
|
|||
|
pNameAddrNew->TimeOutCount = NbtConfig.RemoteTimeoutCount; // Reset it since we are updating it!
|
|||
|
pOrigIpAddrs = pNameAddrDiscard->pIpAddrsList;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IpAddress = pNameAddrNew->IpAddress;
|
|||
|
pLmhSvcGroupList = pNameAddrNew->pLmhSvcGroupList;
|
|||
|
pNameAddrNew->pLmhSvcGroupList = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ((NameAddFlags & (NAME_RESOLVED_BY_DNS | NAME_RESOLVED_BY_CLIENT | NAME_RESOLVED_BY_IP)) &&
|
|||
|
(pNameAddrNew->RemoteCacheLen))
|
|||
|
{
|
|||
|
ASSERT (!pLmhSvcGroupList);
|
|||
|
pNameAddrNew->pRemoteIpAddrs[0].IpAddress = IpAddress;
|
|||
|
|
|||
|
if ((pNameAddrNew->NameAddFlags & NAME_RESOLVED_BY_LMH_P) &&
|
|||
|
(NameAddFlags & NAME_RESOLVED_BY_DNS))
|
|||
|
{
|
|||
|
//
|
|||
|
// If the name was resolved by DNS, then don't overwrite the
|
|||
|
// name entry if it was pre-loaded below
|
|||
|
//
|
|||
|
pNameAddrNew->NameAddFlags |= NameAddFlags;
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((pDeviceContext) &&
|
|||
|
(!IsDeviceNetbiosless(pDeviceContext)) &&
|
|||
|
(pDeviceContext->AdapterNumber < pNameAddrNew->RemoteCacheLen))
|
|||
|
{
|
|||
|
AdapterIndex = pDeviceContext->AdapterNumber;
|
|||
|
pNameAddrNew->AdapterMask |= pDeviceContext->AdapterMask;
|
|||
|
|
|||
|
if (IpAddress)
|
|||
|
{
|
|||
|
pNameAddrNew->IpAddress = IpAddress; // in case we are copying from pNameAddrDiscard
|
|||
|
pNameAddrNew->pRemoteIpAddrs[AdapterIndex].IpAddress = IpAddress; // new addr
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now see if we need to update the Original IP addresses list!
|
|||
|
//
|
|||
|
if (pOrigIpAddrs)
|
|||
|
{
|
|||
|
// pOrigIpAddrs could only have been set earlier if it was obtained from pNameAddrDiscard!
|
|||
|
pNameAddrDiscard->pIpAddrsList = NULL;
|
|||
|
}
|
|||
|
else if (pOrigIpAddrs = pNameAddrNew->pIpAddrsList)
|
|||
|
{
|
|||
|
pNameAddrNew->pIpAddrsList = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pOrigIpAddrs)
|
|||
|
{
|
|||
|
if (pNameAddrNew->pRemoteIpAddrs[AdapterIndex].pOrigIpAddrs)
|
|||
|
{
|
|||
|
CTEFreeMem (pNameAddrNew->pRemoteIpAddrs[AdapterIndex].pOrigIpAddrs);
|
|||
|
}
|
|||
|
pNameAddrNew->pRemoteIpAddrs[AdapterIndex].pOrigIpAddrs = pOrigIpAddrs;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pLmhSvcGroupList)
|
|||
|
{
|
|||
|
ASSERT(NameAddFlags == (NAME_RESOLVED_BY_LMH_P|NAME_ADD_INET_GROUP));
|
|||
|
if (pNameAddrNew->pLmhSvcGroupList) {
|
|||
|
CTEFreeMem (pNameAddrNew->pLmhSvcGroupList);
|
|||
|
}
|
|||
|
|
|||
|
pNameAddrNew->pLmhSvcGroupList = pLmhSvcGroupList;
|
|||
|
}
|
|||
|
|
|||
|
pNameAddrNew->NameAddFlags |= NameAddFlags;
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
LockAndAddToHashTable(
|
|||
|
IN tHASHTABLE *pHashTable,
|
|||
|
IN PCHAR pName,
|
|||
|
IN PCHAR pScope,
|
|||
|
IN tIPADDRESS IpAddress,
|
|||
|
IN enum eNbtAddrType NameType,
|
|||
|
IN tNAMEADDR *pNameAddr,
|
|||
|
OUT tNAMEADDR **ppNameAddress,
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN USHORT NameAddFlags
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
CTESpinLock (&NbtConfig.JointLock, OldIrq);
|
|||
|
|
|||
|
status = AddToHashTable(pHashTable,
|
|||
|
pName,
|
|||
|
pScope,
|
|||
|
IpAddress,
|
|||
|
NameType,
|
|||
|
pNameAddr,
|
|||
|
ppNameAddress,
|
|||
|
pDeviceContext,
|
|||
|
NameAddFlags);
|
|||
|
|
|||
|
CTESpinFree (&NbtConfig.JointLock, OldIrq);
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
AddToHashTable(
|
|||
|
IN tHASHTABLE *pHashTable,
|
|||
|
IN PCHAR pName,
|
|||
|
IN PCHAR pScope,
|
|||
|
IN tIPADDRESS IpAddress,
|
|||
|
IN enum eNbtAddrType NameType,
|
|||
|
IN tNAMEADDR *pNameAddr,
|
|||
|
OUT tNAMEADDR **ppNameAddress,
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN USHORT NameAddFlags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds a name to IPaddress to the hash table
|
|||
|
Called with the spin lock HELD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
tNAMEADDR *pNameAddress;
|
|||
|
tNAMEADDR *pScopeAddr;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG iIndex;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
ULONG i, OldRemoteCacheLen;
|
|||
|
tNAMEADDR *pNameAddrFound;
|
|||
|
tADDRESS_ENTRY *pRemoteCache = NULL;
|
|||
|
BOOLEAN fNameIsAlreadyInCache;
|
|||
|
tIPADDRESS OldIpAddress;
|
|||
|
|
|||
|
if (pNameAddr)
|
|||
|
{
|
|||
|
ASSERT ((pNameAddr->Verify == LOCAL_NAME) || (pNameAddr->Verify == REMOTE_NAME));
|
|||
|
}
|
|||
|
|
|||
|
fNameIsAlreadyInCache = (STATUS_SUCCESS == FindInHashTable(pHashTable,pName,pScope,&pNameAddrFound));
|
|||
|
|
|||
|
if ((fNameIsAlreadyInCache) &&
|
|||
|
(pNameAddrFound->Verify == REMOTE_NAME) &&
|
|||
|
!(pNameAddrFound->NameTypeState & STATE_RELEASED))
|
|||
|
{
|
|||
|
OldIpAddress = pNameAddrFound->IpAddress;
|
|||
|
pNameAddrFound->IpAddress = IpAddress;
|
|||
|
|
|||
|
if (!(NameAddFlags & NAME_ADD_IF_NOT_FOUND_ONLY) &&
|
|||
|
((pNameAddr) ||
|
|||
|
!(pNameAddrFound->NameAddFlags & NAME_ADD_INET_GROUP)))
|
|||
|
{
|
|||
|
//
|
|||
|
// We have a valid existing name, so just update it!
|
|||
|
//
|
|||
|
status = NbtUpdateRemoteName(pDeviceContext, pNameAddrFound, pNameAddr, NameAddFlags);
|
|||
|
if (!NT_SUCCESS (status))
|
|||
|
{
|
|||
|
//
|
|||
|
// We Failed most problably because we were not allowed to
|
|||
|
// over-write or modify the current entry for some reason.
|
|||
|
// So, reset the old IpAddress
|
|||
|
//
|
|||
|
pNameAddrFound->IpAddress = OldIpAddress;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pNameAddr)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT (!(NameAddFlags & NAME_ADD_INET_GROUP));
|
|||
|
}
|
|||
|
|
|||
|
if (ppNameAddress)
|
|||
|
{
|
|||
|
*ppNameAddress = pNameAddrFound;
|
|||
|
}
|
|||
|
|
|||
|
// found it in the table so we're done - return pending to
|
|||
|
// differentiate from the name added case. Pending passes the
|
|||
|
// NT_SUCCESS() test as well as Success does.
|
|||
|
//
|
|||
|
return (STATUS_PENDING);
|
|||
|
}
|
|||
|
|
|||
|
// first hash the name to an index
|
|||
|
// take the lower nibble of the first 2 characters.. mod table size
|
|||
|
iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
|
|||
|
iIndex = iIndex % pHashTable->lNumBuckets;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig,OldIrq);
|
|||
|
|
|||
|
if (!pNameAddr)
|
|||
|
{
|
|||
|
//
|
|||
|
// Allocate memory for another hash table entry
|
|||
|
//
|
|||
|
pNameAddress = (tNAMEADDR *)NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('0'));
|
|||
|
if ((pNameAddress) &&
|
|||
|
(pHashTable->LocalRemote == NBT_REMOTE) &&
|
|||
|
(NbtConfig.RemoteCacheLen) &&
|
|||
|
(!(pRemoteCache = (tADDRESS_ENTRY *)
|
|||
|
NbtAllocMem(NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY),NBT_TAG2('03')))))
|
|||
|
{
|
|||
|
CTEMemFree (pNameAddress);
|
|||
|
pNameAddress = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (!pNameAddress)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig,OldIrq);
|
|||
|
KdPrint (("AddToHashTable: ERROR - INSUFFICIENT_RESOURCES\n"));
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
CTEZeroMemory(pNameAddress,sizeof(tNAMEADDR));
|
|||
|
pNameAddress->IpAddress = IpAddress;
|
|||
|
pNameAddress->NameTypeState = (NameType == NBT_UNIQUE) ? NAMETYPE_UNIQUE : NAMETYPE_GROUP;
|
|||
|
pNameAddress->NameTypeState |= STATE_RESOLVED;
|
|||
|
CTEMemCopy (pNameAddress->Name, pName, (ULONG)NETBIOS_NAME_SIZE); // fill in the name
|
|||
|
|
|||
|
if ((pHashTable->LocalRemote == NBT_LOCAL) ||
|
|||
|
(pHashTable->LocalRemote == NBT_REMOTE_ALLOC_MEM))
|
|||
|
{
|
|||
|
pNameAddress->Verify = LOCAL_NAME;
|
|||
|
NBT_REFERENCE_NAMEADDR (pNameAddress, REF_NAME_LOCAL);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT (!(NameAddFlags & NAME_ADD_INET_GROUP));
|
|||
|
pNameAddress->Verify = REMOTE_NAME;
|
|||
|
CTEZeroMemory(pRemoteCache, NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY));
|
|||
|
pNameAddress->pRemoteIpAddrs = pRemoteCache;
|
|||
|
pNameAddress->RemoteCacheLen = NbtConfig.RemoteCacheLen;
|
|||
|
NBT_REFERENCE_NAMEADDR (pNameAddress, REF_NAME_REMOTE);
|
|||
|
|
|||
|
NbtUpdateRemoteName(pDeviceContext, pNameAddress, NULL, NameAddFlags);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// See if we need to grow the IP addrs cache for remote names
|
|||
|
//
|
|||
|
ASSERT (!pNameAddr->pRemoteIpAddrs);
|
|||
|
if (pNameAddr->Verify == REMOTE_NAME)
|
|||
|
{
|
|||
|
NbtUpdateRemoteName(pDeviceContext, pNameAddr, NULL, NameAddFlags);
|
|||
|
}
|
|||
|
pNameAddress = pNameAddr;
|
|||
|
}
|
|||
|
|
|||
|
pNameAddress->pTimer = NULL;
|
|||
|
pNameAddress->TimeOutCount = NbtConfig.RemoteTimeoutCount;
|
|||
|
|
|||
|
// put on the head of the list in case the same name is in the table
|
|||
|
// twice (where the second one is waiting for its reference count to
|
|||
|
// go to zero, and will ultimately be removed, we want to find the new
|
|||
|
// name on any query of the table
|
|||
|
//
|
|||
|
InsertHeadList(&pHashTable->Bucket[iIndex],&pNameAddress->Linkage);
|
|||
|
|
|||
|
|
|||
|
// check for a scope too ( on non-local names only )
|
|||
|
if ((pHashTable->LocalRemote != NBT_LOCAL) && (*pScope))
|
|||
|
{
|
|||
|
// we must have a scope
|
|||
|
// see if the scope is already in the hash table and add if necessary
|
|||
|
//
|
|||
|
status = FindInHashTable(pHashTable, pScope, NULL, &pScopeAddr);
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
PUCHAR Scope;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
// *TODO* - this check will not adequately protect against
|
|||
|
// bad scopes passed in - i.e. we may run off into memory
|
|||
|
// and get an access violation...however converttoascii should
|
|||
|
// do the protection. For local names the scope should be
|
|||
|
// ok since NBT read it from the registry and checked it first
|
|||
|
//
|
|||
|
iIndex = 0;
|
|||
|
Scope = pScope;
|
|||
|
while (*Scope && (iIndex <= 255))
|
|||
|
{
|
|||
|
iIndex++;
|
|||
|
Scope++;
|
|||
|
}
|
|||
|
|
|||
|
// the whole length must be 255 or less, so the scope can only be
|
|||
|
// 255-16...
|
|||
|
if (iIndex > (255 - NETBIOS_NAME_SIZE))
|
|||
|
{
|
|||
|
RemoveEntryList(&pNameAddress->Linkage);
|
|||
|
if (pNameAddress->pRemoteIpAddrs)
|
|||
|
{
|
|||
|
CTEMemFree ((PVOID)pNameAddress->pRemoteIpAddrs);
|
|||
|
}
|
|||
|
|
|||
|
pNameAddress->Verify += 10;
|
|||
|
CTEMemFree(pNameAddress);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig,OldIrq);
|
|||
|
return(STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
iIndex++; // to copy the null
|
|||
|
|
|||
|
//
|
|||
|
// the scope is a variable length string, so allocate enough
|
|||
|
// memory for the tNameAddr structure based on this string length
|
|||
|
//
|
|||
|
pScopeAddr = (tNAMEADDR *)NbtAllocMem((USHORT)(sizeof(tNAMEADDR)
|
|||
|
+ iIndex
|
|||
|
- NETBIOS_NAME_SIZE),NBT_TAG('1'));
|
|||
|
if ( !pScopeAddr )
|
|||
|
{
|
|||
|
RemoveEntryList(&pNameAddress->Linkage);
|
|||
|
if (pNameAddress->pRemoteIpAddrs)
|
|||
|
{
|
|||
|
CTEMemFree ((PVOID)pNameAddress->pRemoteIpAddrs);
|
|||
|
}
|
|||
|
|
|||
|
pNameAddress->Verify += 10;
|
|||
|
CTEMemFree (pNameAddress);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig,OldIrq);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES ;
|
|||
|
}
|
|||
|
|
|||
|
CTEZeroMemory(pScopeAddr, (sizeof(tNAMEADDR)+iIndex-NETBIOS_NAME_SIZE));
|
|||
|
|
|||
|
// copy the scope to the name field including the Null at the end.
|
|||
|
// to the end of the name
|
|||
|
CTEMemCopy(pScopeAddr->Name,pScope,iIndex);
|
|||
|
|
|||
|
// mark the entry as containing a scope name for cleanup later
|
|||
|
pScopeAddr->NameTypeState = NAMETYPE_SCOPE | STATE_RESOLVED;
|
|||
|
|
|||
|
// keep the size of the name in the context value for easier name
|
|||
|
// comparisons in FindInHashTable
|
|||
|
|
|||
|
pScopeAddr->Verify = REMOTE_NAME;
|
|||
|
NBT_REFERENCE_NAMEADDR (pScopeAddr, REF_NAME_REMOTE);
|
|||
|
NBT_REFERENCE_NAMEADDR (pScopeAddr, REF_NAME_SCOPE);
|
|||
|
pScopeAddr->ulScopeLength = iIndex;
|
|||
|
pNameAddress->pScope = pScopeAddr;
|
|||
|
|
|||
|
// add the scope record to the hash table
|
|||
|
iIndex = ((pScopeAddr->Name[0] & 0x0F) << 4) + (pScopeAddr->Name[1] & 0x0F);
|
|||
|
iIndex = iIndex % pHashTable->lNumBuckets;
|
|||
|
InsertTailList(&pHashTable->Bucket[iIndex],&pScopeAddr->Linkage);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// the scope is already in the hash table so link the name to the
|
|||
|
// scope
|
|||
|
pNameAddress->pScope = pScopeAddr;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pNameAddress->pScope = NULL; // no scope
|
|||
|
}
|
|||
|
|
|||
|
// return the pointer to the hash table block
|
|||
|
if (ppNameAddress)
|
|||
|
{
|
|||
|
// return the pointer to the hash table block
|
|||
|
*ppNameAddress = pNameAddress;
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig,OldIrq);
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
tNAMEADDR *
|
|||
|
LockAndFindName(
|
|||
|
enum eNbtLocation Location,
|
|||
|
PCHAR pName,
|
|||
|
PCHAR pScope,
|
|||
|
ULONG *pRetNameType
|
|||
|
)
|
|||
|
{
|
|||
|
tNAMEADDR *pNameAddr;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
CTESpinLock (&NbtConfig.JointLock, OldIrq);
|
|||
|
|
|||
|
pNameAddr = FindName(Location,
|
|||
|
pName,
|
|||
|
pScope,
|
|||
|
pRetNameType);
|
|||
|
|
|||
|
CTESpinFree (&NbtConfig.JointLock, OldIrq);
|
|||
|
return (pNameAddr);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
tNAMEADDR *
|
|||
|
FindName(
|
|||
|
enum eNbtLocation Location,
|
|||
|
PCHAR pName,
|
|||
|
PCHAR pScope,
|
|||
|
ULONG *pRetNameType
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine searches the name table to find a name. The table searched
|
|||
|
depends on the Location passed in - whether it searches the local table
|
|||
|
or the network names table. The routine checks the state of the name
|
|||
|
and only returns names in the resolved state.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
tNAMEADDR *pNameAddr;
|
|||
|
NTSTATUS status;
|
|||
|
tHASHTABLE *pHashTbl;
|
|||
|
|
|||
|
if (Location == NBT_LOCAL)
|
|||
|
{
|
|||
|
pHashTbl = pNbtGlobConfig->pLocalHashTbl;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pHashTbl = pNbtGlobConfig->pRemoteHashTbl;
|
|||
|
}
|
|||
|
|
|||
|
status = FindInHashTable (pHashTbl, pName, pScope, &pNameAddr);
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
*pRetNameType = pNameAddr->NameTypeState;
|
|||
|
|
|||
|
//
|
|||
|
// Only return names that are in the resolved state
|
|||
|
//
|
|||
|
if (!(pNameAddr->NameTypeState & STATE_RESOLVED))
|
|||
|
{
|
|||
|
pNameAddr = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return(pNameAddr);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
FindInHashTable(
|
|||
|
tHASHTABLE *pHashTable,
|
|||
|
PCHAR pName,
|
|||
|
PCHAR pScope,
|
|||
|
tNAMEADDR **pNameAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks if the name passed in matches a hash table entry.
|
|||
|
Called with the spin lock HELD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PLIST_ENTRY pEntry;
|
|||
|
PLIST_ENTRY pHead;
|
|||
|
tNAMEADDR *pNameAddr;
|
|||
|
int iIndex;
|
|||
|
ULONG uNameSize;
|
|||
|
PCHAR pScopeTbl;
|
|||
|
ULONG uInScopeLength = 0;
|
|||
|
|
|||
|
// first hash the name to an index...
|
|||
|
// take the lower nibble of the first 2 characters.. mod table size
|
|||
|
//
|
|||
|
iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
|
|||
|
iIndex = iIndex % pHashTable->lNumBuckets;
|
|||
|
|
|||
|
if (pScope)
|
|||
|
{
|
|||
|
uInScopeLength = strlen (pScope);
|
|||
|
}
|
|||
|
|
|||
|
// check if the name is already in the table
|
|||
|
// check each entry in the hash list...until the end of the list
|
|||
|
pHead = &pHashTable->Bucket[iIndex];
|
|||
|
pEntry = pHead;
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
|
|||
|
|
|||
|
if (pNameAddr->NameTypeState & NAMETYPE_SCOPE)
|
|||
|
{
|
|||
|
// scope names are treated differently since they are not
|
|||
|
// 16 bytes long... the length is stored separately.
|
|||
|
uNameSize = pNameAddr->ulScopeLength;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
uNameSize = NETBIOS_NAME_SIZE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// strncmp will terminate at the first non-matching byte
|
|||
|
// or when it has matched uNameSize bytes
|
|||
|
//
|
|||
|
// Bug # 225328 -- have to use CTEMemEqu to compare all
|
|||
|
// uNameSize bytes (otherwise bad name can cause termination
|
|||
|
// due to NULL character)
|
|||
|
//
|
|||
|
if (!(pNameAddr->NameTypeState & STATE_RELEASED) &&
|
|||
|
CTEMemEqu (pName, pNameAddr->Name, uNameSize))
|
|||
|
{
|
|||
|
// now check if the scopes match. Scopes are stored differently
|
|||
|
// on the local and remote tables.
|
|||
|
//
|
|||
|
if (!pScope)
|
|||
|
{
|
|||
|
// passing in a Null scope means try to find the name without
|
|||
|
// worrying about a scope matching too...
|
|||
|
*pNameAddress = pNameAddr;
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if Local Hash table
|
|||
|
//
|
|||
|
if (pHashTable == NbtConfig.pLocalHashTbl)
|
|||
|
{
|
|||
|
// In the local hash table case the scope is the same for all
|
|||
|
// names on the node and it is stored in the NbtConfig structure
|
|||
|
pScopeTbl = NbtConfig.pScope;
|
|||
|
uNameSize = NbtConfig.ScopeLength;
|
|||
|
}
|
|||
|
//
|
|||
|
// This is a Remote Hash table lookup
|
|||
|
//
|
|||
|
else if (pNameAddr->pScope)
|
|||
|
{
|
|||
|
pScopeTbl = &pNameAddr->pScope->Name[0];
|
|||
|
uNameSize = pNameAddr->pScope->ulScopeLength;
|
|||
|
}
|
|||
|
//
|
|||
|
// Remote Hash table entry with NULL scope
|
|||
|
// so if passed in scope is also Null, we have a match
|
|||
|
//
|
|||
|
else if (!uInScopeLength)
|
|||
|
{
|
|||
|
*pNameAddress = pNameAddr;
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Hash table scope length is 0 != uInScopeLength
|
|||
|
// ==> No match!
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// strncmp will terminate at the first non-matching byte
|
|||
|
// or when it has matched uNameSize bytes
|
|||
|
//
|
|||
|
if (0 == strncmp (pScope, pScopeTbl, uNameSize))
|
|||
|
{
|
|||
|
// the scopes match so return
|
|||
|
*pNameAddress = pNameAddr;
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
} // end of matching name found
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_UNSUCCESSFUL);
|
|||
|
}
|