Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

844 lines
26 KiB

  1. //
  2. //
  3. // hashtbl.c
  4. //
  5. // This file contains the name code to implement the local and remote
  6. // hash tables used to store local and remote names to IP addresses
  7. // The hash table should not use more than 256 buckets since the hash
  8. // index is only calculated to one byte!
  9. #include "precomp.h"
  10. VOID DestroyHashTable(IN PHASHTABLE pHashTable);
  11. //******************* Pageable Routine Declarations ****************
  12. #ifdef ALLOC_PRAGMA
  13. #pragma CTEMakePageable(INIT, CreateHashTable)
  14. #pragma CTEMakePageable(PAGE, DestroyHashTables)
  15. #pragma CTEMakePageable(PAGE, DestroyHashTable)
  16. #endif
  17. //******************* Pageable Routine Declarations ****************
  18. //----------------------------------------------------------------------------
  19. NTSTATUS
  20. CreateHashTable(
  21. tHASHTABLE **pHashTable,
  22. LONG lNumBuckets,
  23. enum eNbtLocation LocalRemote
  24. )
  25. /*++
  26. Routine Description:
  27. This routine creates a hash table uTableSize long.
  28. Arguments:
  29. Return Value:
  30. The function value is the status of the operation.
  31. --*/
  32. {
  33. ULONG uSize;
  34. LONG i;
  35. NTSTATUS status;
  36. CTEPagedCode();
  37. uSize = (lNumBuckets-1)*sizeof(LIST_ENTRY) + sizeof(tHASHTABLE);
  38. *pHashTable = (tHASHTABLE *) NbtAllocMem (uSize, NBT_TAG2('01'));
  39. if (*pHashTable)
  40. {
  41. // initialize all of the buckets to have null chains off of them
  42. for (i=0;i < lNumBuckets ;i++ )
  43. {
  44. InitializeListHead(&(*pHashTable)->Bucket[i]);
  45. }
  46. (*pHashTable)->LocalRemote = LocalRemote;
  47. (*pHashTable)->lNumBuckets = lNumBuckets;
  48. status = STATUS_SUCCESS;
  49. }
  50. else
  51. {
  52. IF_DBG(NBT_DEBUG_HASHTBL)
  53. KdPrint(("Nbt.CreateHashTable: Unable to create hash table\n"));
  54. status = STATUS_INSUFFICIENT_RESOURCES;
  55. }
  56. return(status);
  57. }
  58. #ifdef _PNP_POWER_
  59. VOID
  60. DestroyHashTable(
  61. IN PHASHTABLE pHashTable
  62. )
  63. {
  64. LONG i, j;
  65. tNAMEADDR *pNameAddr;
  66. LIST_ENTRY *pEntry;
  67. CTEPagedCode();
  68. if (pHashTable == NULL) {
  69. return;
  70. }
  71. /*
  72. * Go through all the buckets to see if there are any names left
  73. */
  74. for (i = 0; i < pHashTable->lNumBuckets; i++) {
  75. while (!IsListEmpty(&(pHashTable->Bucket[i]))) {
  76. pEntry = RemoveHeadList(&(pHashTable->Bucket[i]));
  77. pNameAddr = CONTAINING_RECORD(pEntry, tNAMEADDR, Linkage);
  78. IF_DBG(NBT_DEBUG_HASHTBL)
  79. KdPrint (("netbt!DestroyHashTable: WARNING! Freeing Name: <%16.16s:%x>\n",
  80. pNameAddr->Name, pNameAddr->Name[15]));
  81. /*
  82. * Notify deferencer not to do RemoveListEntry again becaseu we already do it above.
  83. */
  84. if (pNameAddr->Verify == REMOTE_NAME && (pNameAddr->NameTypeState & PRELOADED)) {
  85. ASSERT(pNameAddr->RefCount == 2);
  86. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_PRELOADED, FALSE);
  87. }
  88. ASSERT(pNameAddr->RefCount == 1);
  89. pNameAddr->Linkage.Flink = pNameAddr->Linkage.Blink = NULL;
  90. NBT_DEREFERENCE_NAMEADDR(pNameAddr,((pNameAddr->Verify==LOCAL_NAME)?REF_NAME_LOCAL:REF_NAME_REMOTE),FALSE);
  91. }
  92. }
  93. CTEMemFree(pHashTable);
  94. }
  95. //----------------------------------------------------------------------------
  96. VOID
  97. DestroyHashTables(
  98. )
  99. /*++
  100. Routine Description:
  101. This routine destroys a hash table and frees the entries in NumBuckets
  102. It Must be called with the NbtConfig lock held!
  103. Arguments:
  104. Return Value:
  105. The function value is the status of the operation.
  106. --*/
  107. {
  108. CTEPagedCode();
  109. IF_DBG(NBT_DEBUG_HASHTBL)
  110. KdPrint (("netbt!DestroyHashTables: destroying remote hash table ..."));
  111. DestroyHashTable(NbtConfig.pRemoteHashTbl);
  112. NbtConfig.pRemoteHashTbl = NULL;
  113. IF_DBG(NBT_DEBUG_HASHTBL)
  114. KdPrint (("\nnetbt!DestroyHashTables: destroying local hash table ..."));
  115. DestroyHashTable(NbtConfig.pLocalHashTbl);
  116. NbtConfig.pLocalHashTbl = NULL;
  117. IF_DBG(NBT_DEBUG_HASHTBL)
  118. KdPrint (("\n"));
  119. }
  120. #endif // _PNP_POWER_
  121. //----------------------------------------------------------------------------
  122. NTSTATUS
  123. NbtUpdateRemoteName(
  124. IN tDEVICECONTEXT *pDeviceContext,
  125. IN tNAMEADDR *pNameAddrNew,
  126. IN tNAMEADDR *pNameAddrDiscard,
  127. IN USHORT NameAddFlags
  128. )
  129. {
  130. tIPADDRESS IpAddress;
  131. tIPADDRESS *pLmhSvcGroupList = NULL;
  132. tIPADDRESS *pOrigIpAddrs = NULL;
  133. ULONG AdapterIndex = 0; // by default
  134. ULONG i;
  135. ASSERT (pNameAddrNew);
  136. //
  137. // See if we need to grow the IP addrs cache for the cached name
  138. //
  139. if (pNameAddrNew->RemoteCacheLen < NbtConfig.RemoteCacheLen) {
  140. tADDRESS_ENTRY *pRemoteCache;
  141. pRemoteCache = (tADDRESS_ENTRY *)NbtAllocMem(NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY),NBT_TAG2('02'));
  142. if (pRemoteCache) {
  143. CTEZeroMemory(pRemoteCache, NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY));
  144. /*
  145. * Copy data from and free the previous cache (if any)
  146. */
  147. if (pNameAddrNew->pRemoteIpAddrs) {
  148. CTEMemCopy (pRemoteCache, pNameAddrNew->pRemoteIpAddrs,
  149. sizeof(tADDRESS_ENTRY) * pNameAddrNew->RemoteCacheLen);
  150. CTEFreeMem (pNameAddrNew->pRemoteIpAddrs)
  151. }
  152. pNameAddrNew->pRemoteIpAddrs = pRemoteCache;
  153. pNameAddrNew->RemoteCacheLen = NbtConfig.RemoteCacheLen;
  154. } else {
  155. KdPrint(("Nbt.NbtUpdateRemoteName: FAILed to expand Cache entry!\n"));
  156. }
  157. }
  158. //
  159. // If the new entry being added replaces an entry which was
  160. // either pre-loaded or set by a client, and the new entry itself
  161. // does not have that flag set, then ignore this update.
  162. //
  163. ASSERT (NAME_RESOLVED_BY_DNS > NAME_RESOLVED_BY_LMH_P); // For the check below to succeed!
  164. if (((pNameAddrNew->NameAddFlags & NAME_RESOLVED_BY_CLIENT) &&
  165. !(NameAddFlags & NAME_RESOLVED_BY_CLIENT)) ||
  166. ((pNameAddrNew->NameAddFlags & NAME_RESOLVED_BY_LMH_P) >
  167. (NameAddFlags & (NAME_RESOLVED_BY_LMH_P | NAME_RESOLVED_BY_DNS))))
  168. {
  169. return (STATUS_UNSUCCESSFUL);
  170. }
  171. if (pNameAddrDiscard)
  172. {
  173. IpAddress = pNameAddrDiscard->IpAddress;
  174. pLmhSvcGroupList = pNameAddrDiscard->pLmhSvcGroupList;
  175. pNameAddrDiscard->pLmhSvcGroupList = NULL;
  176. pNameAddrNew->TimeOutCount = NbtConfig.RemoteTimeoutCount; // Reset it since we are updating it!
  177. pOrigIpAddrs = pNameAddrDiscard->pIpAddrsList;
  178. }
  179. else
  180. {
  181. IpAddress = pNameAddrNew->IpAddress;
  182. pLmhSvcGroupList = pNameAddrNew->pLmhSvcGroupList;
  183. pNameAddrNew->pLmhSvcGroupList = NULL;
  184. }
  185. if ((NameAddFlags & (NAME_RESOLVED_BY_DNS | NAME_RESOLVED_BY_CLIENT | NAME_RESOLVED_BY_IP)) &&
  186. (pNameAddrNew->RemoteCacheLen))
  187. {
  188. ASSERT (!pLmhSvcGroupList);
  189. pNameAddrNew->pRemoteIpAddrs[0].IpAddress = IpAddress;
  190. if ((pNameAddrNew->NameAddFlags & NAME_RESOLVED_BY_LMH_P) &&
  191. (NameAddFlags & NAME_RESOLVED_BY_DNS))
  192. {
  193. //
  194. // If the name was resolved by DNS, then don't overwrite the
  195. // name entry if it was pre-loaded below
  196. //
  197. pNameAddrNew->NameAddFlags |= NameAddFlags;
  198. return (STATUS_SUCCESS);
  199. }
  200. }
  201. if ((pDeviceContext) &&
  202. (!IsDeviceNetbiosless(pDeviceContext)) &&
  203. (pDeviceContext->AdapterNumber < pNameAddrNew->RemoteCacheLen))
  204. {
  205. AdapterIndex = pDeviceContext->AdapterNumber;
  206. pNameAddrNew->AdapterMask |= pDeviceContext->AdapterMask;
  207. if (IpAddress)
  208. {
  209. pNameAddrNew->IpAddress = IpAddress; // in case we are copying from pNameAddrDiscard
  210. pNameAddrNew->pRemoteIpAddrs[AdapterIndex].IpAddress = IpAddress; // new addr
  211. }
  212. //
  213. // Now see if we need to update the Original IP addresses list!
  214. //
  215. if (pOrigIpAddrs)
  216. {
  217. // pOrigIpAddrs could only have been set earlier if it was obtained from pNameAddrDiscard!
  218. pNameAddrDiscard->pIpAddrsList = NULL;
  219. }
  220. else if (pOrigIpAddrs = pNameAddrNew->pIpAddrsList)
  221. {
  222. pNameAddrNew->pIpAddrsList = NULL;
  223. }
  224. if (pOrigIpAddrs)
  225. {
  226. if (pNameAddrNew->pRemoteIpAddrs[AdapterIndex].pOrigIpAddrs)
  227. {
  228. CTEFreeMem (pNameAddrNew->pRemoteIpAddrs[AdapterIndex].pOrigIpAddrs);
  229. }
  230. pNameAddrNew->pRemoteIpAddrs[AdapterIndex].pOrigIpAddrs = pOrigIpAddrs;
  231. }
  232. }
  233. if (pLmhSvcGroupList)
  234. {
  235. ASSERT(NameAddFlags == (NAME_RESOLVED_BY_LMH_P|NAME_ADD_INET_GROUP));
  236. if (pNameAddrNew->pLmhSvcGroupList) {
  237. CTEFreeMem (pNameAddrNew->pLmhSvcGroupList);
  238. }
  239. pNameAddrNew->pLmhSvcGroupList = pLmhSvcGroupList;
  240. }
  241. pNameAddrNew->NameAddFlags |= NameAddFlags;
  242. return (STATUS_SUCCESS);
  243. }
  244. //----------------------------------------------------------------------------
  245. NTSTATUS
  246. LockAndAddToHashTable(
  247. IN tHASHTABLE *pHashTable,
  248. IN PCHAR pName,
  249. IN PCHAR pScope,
  250. IN tIPADDRESS IpAddress,
  251. IN enum eNbtAddrType NameType,
  252. IN tNAMEADDR *pNameAddr,
  253. OUT tNAMEADDR **ppNameAddress,
  254. IN tDEVICECONTEXT *pDeviceContext,
  255. IN USHORT NameAddFlags
  256. )
  257. {
  258. NTSTATUS status;
  259. CTELockHandle OldIrq;
  260. CTESpinLock (&NbtConfig.JointLock, OldIrq);
  261. status = AddToHashTable(pHashTable,
  262. pName,
  263. pScope,
  264. IpAddress,
  265. NameType,
  266. pNameAddr,
  267. ppNameAddress,
  268. pDeviceContext,
  269. NameAddFlags);
  270. CTESpinFree (&NbtConfig.JointLock, OldIrq);
  271. return (status);
  272. }
  273. //----------------------------------------------------------------------------
  274. NTSTATUS
  275. AddToHashTable(
  276. IN tHASHTABLE *pHashTable,
  277. IN PCHAR pName,
  278. IN PCHAR pScope,
  279. IN tIPADDRESS IpAddress,
  280. IN enum eNbtAddrType NameType,
  281. IN tNAMEADDR *pNameAddr,
  282. OUT tNAMEADDR **ppNameAddress,
  283. IN tDEVICECONTEXT *pDeviceContext,
  284. IN USHORT NameAddFlags
  285. )
  286. /*++
  287. Routine Description:
  288. This routine adds a name to IPaddress to the hash table
  289. Called with the spin lock HELD.
  290. Arguments:
  291. Return Value:
  292. The function value is the status of the operation.
  293. --*/
  294. {
  295. tNAMEADDR *pNameAddress;
  296. tNAMEADDR *pScopeAddr;
  297. NTSTATUS status;
  298. ULONG iIndex;
  299. CTELockHandle OldIrq;
  300. ULONG i, OldRemoteCacheLen;
  301. tNAMEADDR *pNameAddrFound;
  302. tADDRESS_ENTRY *pRemoteCache = NULL;
  303. BOOLEAN fNameIsAlreadyInCache;
  304. tIPADDRESS OldIpAddress;
  305. if (pNameAddr)
  306. {
  307. ASSERT ((pNameAddr->Verify == LOCAL_NAME) || (pNameAddr->Verify == REMOTE_NAME));
  308. }
  309. fNameIsAlreadyInCache = (STATUS_SUCCESS == FindInHashTable(pHashTable,pName,pScope,&pNameAddrFound));
  310. if ((fNameIsAlreadyInCache) &&
  311. (pNameAddrFound->Verify == REMOTE_NAME) &&
  312. !(pNameAddrFound->NameTypeState & STATE_RELEASED))
  313. {
  314. OldIpAddress = pNameAddrFound->IpAddress;
  315. pNameAddrFound->IpAddress = IpAddress;
  316. if (!(NameAddFlags & NAME_ADD_IF_NOT_FOUND_ONLY) &&
  317. ((pNameAddr) ||
  318. !(pNameAddrFound->NameAddFlags & NAME_ADD_INET_GROUP)))
  319. {
  320. //
  321. // We have a valid existing name, so just update it!
  322. //
  323. status = NbtUpdateRemoteName(pDeviceContext, pNameAddrFound, pNameAddr, NameAddFlags);
  324. if (!NT_SUCCESS (status))
  325. {
  326. //
  327. // We Failed most problably because we were not allowed to
  328. // over-write or modify the current entry for some reason.
  329. // So, reset the old IpAddress
  330. //
  331. pNameAddrFound->IpAddress = OldIpAddress;
  332. }
  333. }
  334. if (pNameAddr)
  335. {
  336. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  337. }
  338. else
  339. {
  340. ASSERT (!(NameAddFlags & NAME_ADD_INET_GROUP));
  341. }
  342. if (ppNameAddress)
  343. {
  344. *ppNameAddress = pNameAddrFound;
  345. }
  346. // found it in the table so we're done - return pending to
  347. // differentiate from the name added case. Pending passes the
  348. // NT_SUCCESS() test as well as Success does.
  349. //
  350. return (STATUS_PENDING);
  351. }
  352. // first hash the name to an index
  353. // take the lower nibble of the first 2 characters.. mod table size
  354. iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
  355. iIndex = iIndex % pHashTable->lNumBuckets;
  356. CTESpinLock(&NbtConfig,OldIrq);
  357. if (!pNameAddr)
  358. {
  359. //
  360. // Allocate memory for another hash table entry
  361. //
  362. pNameAddress = (tNAMEADDR *)NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('0'));
  363. if ((pNameAddress) &&
  364. (pHashTable->LocalRemote == NBT_REMOTE) &&
  365. (NbtConfig.RemoteCacheLen) &&
  366. (!(pRemoteCache = (tADDRESS_ENTRY *)
  367. NbtAllocMem(NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY),NBT_TAG2('03')))))
  368. {
  369. CTEMemFree (pNameAddress);
  370. pNameAddress = NULL;
  371. }
  372. if (!pNameAddress)
  373. {
  374. CTESpinFree(&NbtConfig,OldIrq);
  375. KdPrint (("AddToHashTable: ERROR - INSUFFICIENT_RESOURCES\n"));
  376. return(STATUS_INSUFFICIENT_RESOURCES);
  377. }
  378. CTEZeroMemory(pNameAddress,sizeof(tNAMEADDR));
  379. pNameAddress->IpAddress = IpAddress;
  380. pNameAddress->NameTypeState = (NameType == NBT_UNIQUE) ? NAMETYPE_UNIQUE : NAMETYPE_GROUP;
  381. pNameAddress->NameTypeState |= STATE_RESOLVED;
  382. CTEMemCopy (pNameAddress->Name, pName, (ULONG)NETBIOS_NAME_SIZE); // fill in the name
  383. if ((pHashTable->LocalRemote == NBT_LOCAL) ||
  384. (pHashTable->LocalRemote == NBT_REMOTE_ALLOC_MEM))
  385. {
  386. pNameAddress->Verify = LOCAL_NAME;
  387. NBT_REFERENCE_NAMEADDR (pNameAddress, REF_NAME_LOCAL);
  388. }
  389. else
  390. {
  391. ASSERT (!(NameAddFlags & NAME_ADD_INET_GROUP));
  392. pNameAddress->Verify = REMOTE_NAME;
  393. CTEZeroMemory(pRemoteCache, NbtConfig.RemoteCacheLen*sizeof(tADDRESS_ENTRY));
  394. pNameAddress->pRemoteIpAddrs = pRemoteCache;
  395. pNameAddress->RemoteCacheLen = NbtConfig.RemoteCacheLen;
  396. NBT_REFERENCE_NAMEADDR (pNameAddress, REF_NAME_REMOTE);
  397. NbtUpdateRemoteName(pDeviceContext, pNameAddress, NULL, NameAddFlags);
  398. }
  399. }
  400. else
  401. {
  402. //
  403. // See if we need to grow the IP addrs cache for remote names
  404. //
  405. ASSERT (!pNameAddr->pRemoteIpAddrs);
  406. if (pNameAddr->Verify == REMOTE_NAME)
  407. {
  408. NbtUpdateRemoteName(pDeviceContext, pNameAddr, NULL, NameAddFlags);
  409. }
  410. pNameAddress = pNameAddr;
  411. }
  412. pNameAddress->pTimer = NULL;
  413. pNameAddress->TimeOutCount = NbtConfig.RemoteTimeoutCount;
  414. // put on the head of the list in case the same name is in the table
  415. // twice (where the second one is waiting for its reference count to
  416. // go to zero, and will ultimately be removed, we want to find the new
  417. // name on any query of the table
  418. //
  419. InsertHeadList(&pHashTable->Bucket[iIndex],&pNameAddress->Linkage);
  420. if (pHashTable->LocalRemote == NBT_REMOTE) {
  421. NbtConfig.NumNameCached++;
  422. }
  423. // check for a scope too ( on non-local names only )
  424. if ((pHashTable->LocalRemote != NBT_LOCAL) && (*pScope))
  425. {
  426. // we must have a scope
  427. // see if the scope is already in the hash table and add if necessary
  428. //
  429. status = FindInHashTable(pHashTable, pScope, NULL, &pScopeAddr);
  430. if (!NT_SUCCESS(status))
  431. {
  432. PUCHAR Scope;
  433. status = STATUS_SUCCESS;
  434. // *TODO* - this check will not adequately protect against
  435. // bad scopes passed in - i.e. we may run off into memory
  436. // and get an access violation...however converttoascii should
  437. // do the protection. For local names the scope should be
  438. // ok since NBT read it from the registry and checked it first
  439. //
  440. iIndex = 0;
  441. Scope = pScope;
  442. while (*Scope && (iIndex <= 255))
  443. {
  444. iIndex++;
  445. Scope++;
  446. }
  447. // the whole length must be 255 or less, so the scope can only be
  448. // 255-16...
  449. if (iIndex > (255 - NETBIOS_NAME_SIZE))
  450. {
  451. RemoveEntryList(&pNameAddress->Linkage);
  452. if (pNameAddress->pRemoteIpAddrs)
  453. {
  454. CTEMemFree ((PVOID)pNameAddress->pRemoteIpAddrs);
  455. }
  456. pNameAddress->Verify += 10;
  457. CTEMemFree(pNameAddress);
  458. CTESpinFree(&NbtConfig,OldIrq);
  459. return(STATUS_UNSUCCESSFUL);
  460. }
  461. iIndex++; // to copy the null
  462. //
  463. // the scope is a variable length string, so allocate enough
  464. // memory for the tNameAddr structure based on this string length
  465. //
  466. pScopeAddr = (tNAMEADDR *)NbtAllocMem((USHORT)(sizeof(tNAMEADDR)
  467. + iIndex
  468. - NETBIOS_NAME_SIZE),NBT_TAG('1'));
  469. if ( !pScopeAddr )
  470. {
  471. RemoveEntryList(&pNameAddress->Linkage);
  472. if (pNameAddress->pRemoteIpAddrs)
  473. {
  474. CTEMemFree ((PVOID)pNameAddress->pRemoteIpAddrs);
  475. }
  476. pNameAddress->Verify += 10;
  477. CTEMemFree (pNameAddress);
  478. CTESpinFree(&NbtConfig,OldIrq);
  479. return STATUS_INSUFFICIENT_RESOURCES ;
  480. }
  481. CTEZeroMemory(pScopeAddr, (sizeof(tNAMEADDR)+iIndex-NETBIOS_NAME_SIZE));
  482. // copy the scope to the name field including the Null at the end.
  483. // to the end of the name
  484. CTEMemCopy(pScopeAddr->Name,pScope,iIndex);
  485. // mark the entry as containing a scope name for cleanup later
  486. pScopeAddr->NameTypeState = NAMETYPE_SCOPE | STATE_RESOLVED;
  487. // keep the size of the name in the context value for easier name
  488. // comparisons in FindInHashTable
  489. pScopeAddr->Verify = REMOTE_NAME;
  490. NBT_REFERENCE_NAMEADDR (pScopeAddr, REF_NAME_REMOTE);
  491. NBT_REFERENCE_NAMEADDR (pScopeAddr, REF_NAME_SCOPE);
  492. pScopeAddr->ulScopeLength = iIndex;
  493. pNameAddress->pScope = pScopeAddr;
  494. // add the scope record to the hash table
  495. iIndex = ((pScopeAddr->Name[0] & 0x0F) << 4) + (pScopeAddr->Name[1] & 0x0F);
  496. iIndex = iIndex % pHashTable->lNumBuckets;
  497. InsertTailList(&pHashTable->Bucket[iIndex],&pScopeAddr->Linkage);
  498. if (pHashTable->LocalRemote == NBT_REMOTE) {
  499. NbtConfig.NumNameCached++;
  500. }
  501. }
  502. else
  503. {
  504. // the scope is already in the hash table so link the name to the
  505. // scope
  506. pNameAddress->pScope = pScopeAddr;
  507. }
  508. }
  509. else
  510. {
  511. pNameAddress->pScope = NULL; // no scope
  512. }
  513. // return the pointer to the hash table block
  514. if (ppNameAddress)
  515. {
  516. // return the pointer to the hash table block
  517. *ppNameAddress = pNameAddress;
  518. }
  519. CTESpinFree(&NbtConfig,OldIrq);
  520. return(STATUS_SUCCESS);
  521. }
  522. //----------------------------------------------------------------------------
  523. tNAMEADDR *
  524. LockAndFindName(
  525. enum eNbtLocation Location,
  526. PCHAR pName,
  527. PCHAR pScope,
  528. ULONG *pRetNameType
  529. )
  530. {
  531. tNAMEADDR *pNameAddr;
  532. CTELockHandle OldIrq;
  533. CTESpinLock (&NbtConfig.JointLock, OldIrq);
  534. pNameAddr = FindName(Location,
  535. pName,
  536. pScope,
  537. pRetNameType);
  538. CTESpinFree (&NbtConfig.JointLock, OldIrq);
  539. return (pNameAddr);
  540. }
  541. //----------------------------------------------------------------------------
  542. tNAMEADDR *
  543. FindName(
  544. enum eNbtLocation Location,
  545. PCHAR pName,
  546. PCHAR pScope,
  547. ULONG *pRetNameType
  548. )
  549. /*++
  550. Routine Description:
  551. This routine searches the name table to find a name. The table searched
  552. depends on the Location passed in - whether it searches the local table
  553. or the network names table. The routine checks the state of the name
  554. and only returns names in the resolved state.
  555. Arguments:
  556. Return Value:
  557. The function value is the status of the operation.
  558. --*/
  559. {
  560. tNAMEADDR *pNameAddr;
  561. NTSTATUS status;
  562. tHASHTABLE *pHashTbl;
  563. if (Location == NBT_LOCAL)
  564. {
  565. pHashTbl = pNbtGlobConfig->pLocalHashTbl;
  566. }
  567. else
  568. {
  569. pHashTbl = pNbtGlobConfig->pRemoteHashTbl;
  570. }
  571. status = FindInHashTable (pHashTbl, pName, pScope, &pNameAddr);
  572. if (!NT_SUCCESS(status))
  573. {
  574. return(NULL);
  575. }
  576. *pRetNameType = pNameAddr->NameTypeState;
  577. //
  578. // Only return names that are in the resolved state
  579. //
  580. if (!(pNameAddr->NameTypeState & STATE_RESOLVED))
  581. {
  582. pNameAddr = NULL;
  583. }
  584. return(pNameAddr);
  585. }
  586. //----------------------------------------------------------------------------
  587. NTSTATUS
  588. FindInHashTable(
  589. tHASHTABLE *pHashTable,
  590. PCHAR pName,
  591. PCHAR pScope,
  592. tNAMEADDR **pNameAddress
  593. )
  594. /*++
  595. Routine Description:
  596. This routine checks if the name passed in matches a hash table entry.
  597. Called with the spin lock HELD.
  598. Arguments:
  599. Return Value:
  600. The function value is the status of the operation.
  601. --*/
  602. {
  603. PLIST_ENTRY pEntry;
  604. PLIST_ENTRY pHead;
  605. tNAMEADDR *pNameAddr;
  606. int iIndex;
  607. ULONG uNameSize;
  608. PCHAR pScopeTbl;
  609. ULONG uInScopeLength = 0;
  610. // first hash the name to an index...
  611. // take the lower nibble of the first 2 characters.. mod table size
  612. //
  613. iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
  614. iIndex = iIndex % pHashTable->lNumBuckets;
  615. if (pScope)
  616. {
  617. uInScopeLength = strlen (pScope);
  618. }
  619. // check if the name is already in the table
  620. // check each entry in the hash list...until the end of the list
  621. pHead = &pHashTable->Bucket[iIndex];
  622. pEntry = pHead;
  623. while ((pEntry = pEntry->Flink) != pHead)
  624. {
  625. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  626. if (pNameAddr->NameTypeState & NAMETYPE_SCOPE)
  627. {
  628. // scope names are treated differently since they are not
  629. // 16 bytes long... the length is stored separately.
  630. uNameSize = pNameAddr->ulScopeLength;
  631. }
  632. else
  633. {
  634. uNameSize = NETBIOS_NAME_SIZE;
  635. }
  636. //
  637. // strncmp will terminate at the first non-matching byte
  638. // or when it has matched uNameSize bytes
  639. //
  640. // Bug # 225328 -- have to use CTEMemEqu to compare all
  641. // uNameSize bytes (otherwise bad name can cause termination
  642. // due to NULL character)
  643. //
  644. if (!(pNameAddr->NameTypeState & STATE_RELEASED) &&
  645. CTEMemEqu (pName, pNameAddr->Name, uNameSize))
  646. {
  647. // now check if the scopes match. Scopes are stored differently
  648. // on the local and remote tables.
  649. //
  650. if (!pScope)
  651. {
  652. // passing in a Null scope means try to find the name without
  653. // worrying about a scope matching too...
  654. *pNameAddress = pNameAddr;
  655. return(STATUS_SUCCESS);
  656. }
  657. //
  658. // Check if Local Hash table
  659. //
  660. if (pHashTable == NbtConfig.pLocalHashTbl)
  661. {
  662. // In the local hash table case the scope is the same for all
  663. // names on the node and it is stored in the NbtConfig structure
  664. pScopeTbl = NbtConfig.pScope;
  665. uNameSize = NbtConfig.ScopeLength;
  666. }
  667. //
  668. // This is a Remote Hash table lookup
  669. //
  670. else if (pNameAddr->pScope)
  671. {
  672. pScopeTbl = &pNameAddr->pScope->Name[0];
  673. uNameSize = pNameAddr->pScope->ulScopeLength;
  674. }
  675. //
  676. // Remote Hash table entry with NULL scope
  677. // so if passed in scope is also Null, we have a match
  678. //
  679. else if (!uInScopeLength)
  680. {
  681. *pNameAddress = pNameAddr;
  682. return(STATUS_SUCCESS);
  683. }
  684. else
  685. {
  686. //
  687. // Hash table scope length is 0 != uInScopeLength
  688. // ==> No match!
  689. //
  690. continue;
  691. }
  692. //
  693. // strncmp will terminate at the first non-matching byte
  694. // or when it has matched uNameSize bytes
  695. //
  696. if (0 == strncmp (pScope, pScopeTbl, uNameSize))
  697. {
  698. // the scopes match so return
  699. *pNameAddress = pNameAddr;
  700. return(STATUS_SUCCESS);
  701. }
  702. } // end of matching name found
  703. }
  704. return(STATUS_UNSUCCESSFUL);
  705. }