Source code of Windows XP (NT5)
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.

839 lines
25 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. // check for a scope too ( on non-local names only )
  421. if ((pHashTable->LocalRemote != NBT_LOCAL) && (*pScope))
  422. {
  423. // we must have a scope
  424. // see if the scope is already in the hash table and add if necessary
  425. //
  426. status = FindInHashTable(pHashTable, pScope, NULL, &pScopeAddr);
  427. if (!NT_SUCCESS(status))
  428. {
  429. PUCHAR Scope;
  430. status = STATUS_SUCCESS;
  431. // *TODO* - this check will not adequately protect against
  432. // bad scopes passed in - i.e. we may run off into memory
  433. // and get an access violation...however converttoascii should
  434. // do the protection. For local names the scope should be
  435. // ok since NBT read it from the registry and checked it first
  436. //
  437. iIndex = 0;
  438. Scope = pScope;
  439. while (*Scope && (iIndex <= 255))
  440. {
  441. iIndex++;
  442. Scope++;
  443. }
  444. // the whole length must be 255 or less, so the scope can only be
  445. // 255-16...
  446. if (iIndex > (255 - NETBIOS_NAME_SIZE))
  447. {
  448. RemoveEntryList(&pNameAddress->Linkage);
  449. if (pNameAddress->pRemoteIpAddrs)
  450. {
  451. CTEMemFree ((PVOID)pNameAddress->pRemoteIpAddrs);
  452. }
  453. pNameAddress->Verify += 10;
  454. CTEMemFree(pNameAddress);
  455. CTESpinFree(&NbtConfig,OldIrq);
  456. return(STATUS_UNSUCCESSFUL);
  457. }
  458. iIndex++; // to copy the null
  459. //
  460. // the scope is a variable length string, so allocate enough
  461. // memory for the tNameAddr structure based on this string length
  462. //
  463. pScopeAddr = (tNAMEADDR *)NbtAllocMem((USHORT)(sizeof(tNAMEADDR)
  464. + iIndex
  465. - NETBIOS_NAME_SIZE),NBT_TAG('1'));
  466. if ( !pScopeAddr )
  467. {
  468. RemoveEntryList(&pNameAddress->Linkage);
  469. if (pNameAddress->pRemoteIpAddrs)
  470. {
  471. CTEMemFree ((PVOID)pNameAddress->pRemoteIpAddrs);
  472. }
  473. pNameAddress->Verify += 10;
  474. CTEMemFree (pNameAddress);
  475. CTESpinFree(&NbtConfig,OldIrq);
  476. return STATUS_INSUFFICIENT_RESOURCES ;
  477. }
  478. CTEZeroMemory(pScopeAddr, (sizeof(tNAMEADDR)+iIndex-NETBIOS_NAME_SIZE));
  479. // copy the scope to the name field including the Null at the end.
  480. // to the end of the name
  481. CTEMemCopy(pScopeAddr->Name,pScope,iIndex);
  482. // mark the entry as containing a scope name for cleanup later
  483. pScopeAddr->NameTypeState = NAMETYPE_SCOPE | STATE_RESOLVED;
  484. // keep the size of the name in the context value for easier name
  485. // comparisons in FindInHashTable
  486. pScopeAddr->Verify = REMOTE_NAME;
  487. NBT_REFERENCE_NAMEADDR (pScopeAddr, REF_NAME_REMOTE);
  488. NBT_REFERENCE_NAMEADDR (pScopeAddr, REF_NAME_SCOPE);
  489. pScopeAddr->ulScopeLength = iIndex;
  490. pNameAddress->pScope = pScopeAddr;
  491. // add the scope record to the hash table
  492. iIndex = ((pScopeAddr->Name[0] & 0x0F) << 4) + (pScopeAddr->Name[1] & 0x0F);
  493. iIndex = iIndex % pHashTable->lNumBuckets;
  494. InsertTailList(&pHashTable->Bucket[iIndex],&pScopeAddr->Linkage);
  495. }
  496. else
  497. {
  498. // the scope is already in the hash table so link the name to the
  499. // scope
  500. pNameAddress->pScope = pScopeAddr;
  501. }
  502. }
  503. else
  504. {
  505. pNameAddress->pScope = NULL; // no scope
  506. }
  507. // return the pointer to the hash table block
  508. if (ppNameAddress)
  509. {
  510. // return the pointer to the hash table block
  511. *ppNameAddress = pNameAddress;
  512. }
  513. CTESpinFree(&NbtConfig,OldIrq);
  514. return(STATUS_SUCCESS);
  515. }
  516. //----------------------------------------------------------------------------
  517. tNAMEADDR *
  518. LockAndFindName(
  519. enum eNbtLocation Location,
  520. PCHAR pName,
  521. PCHAR pScope,
  522. ULONG *pRetNameType
  523. )
  524. {
  525. tNAMEADDR *pNameAddr;
  526. CTELockHandle OldIrq;
  527. CTESpinLock (&NbtConfig.JointLock, OldIrq);
  528. pNameAddr = FindName(Location,
  529. pName,
  530. pScope,
  531. pRetNameType);
  532. CTESpinFree (&NbtConfig.JointLock, OldIrq);
  533. return (pNameAddr);
  534. }
  535. //----------------------------------------------------------------------------
  536. tNAMEADDR *
  537. FindName(
  538. enum eNbtLocation Location,
  539. PCHAR pName,
  540. PCHAR pScope,
  541. ULONG *pRetNameType
  542. )
  543. /*++
  544. Routine Description:
  545. This routine searches the name table to find a name. The table searched
  546. depends on the Location passed in - whether it searches the local table
  547. or the network names table. The routine checks the state of the name
  548. and only returns names in the resolved state.
  549. Arguments:
  550. Return Value:
  551. The function value is the status of the operation.
  552. --*/
  553. {
  554. tNAMEADDR *pNameAddr;
  555. NTSTATUS status;
  556. tHASHTABLE *pHashTbl;
  557. if (Location == NBT_LOCAL)
  558. {
  559. pHashTbl = pNbtGlobConfig->pLocalHashTbl;
  560. }
  561. else
  562. {
  563. pHashTbl = pNbtGlobConfig->pRemoteHashTbl;
  564. }
  565. status = FindInHashTable (pHashTbl, pName, pScope, &pNameAddr);
  566. if (!NT_SUCCESS(status))
  567. {
  568. return(NULL);
  569. }
  570. *pRetNameType = pNameAddr->NameTypeState;
  571. //
  572. // Only return names that are in the resolved state
  573. //
  574. if (!(pNameAddr->NameTypeState & STATE_RESOLVED))
  575. {
  576. pNameAddr = NULL;
  577. }
  578. return(pNameAddr);
  579. }
  580. //----------------------------------------------------------------------------
  581. NTSTATUS
  582. FindInHashTable(
  583. tHASHTABLE *pHashTable,
  584. PCHAR pName,
  585. PCHAR pScope,
  586. tNAMEADDR **pNameAddress
  587. )
  588. /*++
  589. Routine Description:
  590. This routine checks if the name passed in matches a hash table entry.
  591. Called with the spin lock HELD.
  592. Arguments:
  593. Return Value:
  594. The function value is the status of the operation.
  595. --*/
  596. {
  597. PLIST_ENTRY pEntry;
  598. PLIST_ENTRY pHead;
  599. tNAMEADDR *pNameAddr;
  600. int iIndex;
  601. ULONG uNameSize;
  602. PCHAR pScopeTbl;
  603. ULONG uInScopeLength = 0;
  604. // first hash the name to an index...
  605. // take the lower nibble of the first 2 characters.. mod table size
  606. //
  607. iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
  608. iIndex = iIndex % pHashTable->lNumBuckets;
  609. if (pScope)
  610. {
  611. uInScopeLength = strlen (pScope);
  612. }
  613. // check if the name is already in the table
  614. // check each entry in the hash list...until the end of the list
  615. pHead = &pHashTable->Bucket[iIndex];
  616. pEntry = pHead;
  617. while ((pEntry = pEntry->Flink) != pHead)
  618. {
  619. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  620. if (pNameAddr->NameTypeState & NAMETYPE_SCOPE)
  621. {
  622. // scope names are treated differently since they are not
  623. // 16 bytes long... the length is stored separately.
  624. uNameSize = pNameAddr->ulScopeLength;
  625. }
  626. else
  627. {
  628. uNameSize = NETBIOS_NAME_SIZE;
  629. }
  630. //
  631. // strncmp will terminate at the first non-matching byte
  632. // or when it has matched uNameSize bytes
  633. //
  634. // Bug # 225328 -- have to use CTEMemEqu to compare all
  635. // uNameSize bytes (otherwise bad name can cause termination
  636. // due to NULL character)
  637. //
  638. if (!(pNameAddr->NameTypeState & STATE_RELEASED) &&
  639. CTEMemEqu (pName, pNameAddr->Name, uNameSize))
  640. {
  641. // now check if the scopes match. Scopes are stored differently
  642. // on the local and remote tables.
  643. //
  644. if (!pScope)
  645. {
  646. // passing in a Null scope means try to find the name without
  647. // worrying about a scope matching too...
  648. *pNameAddress = pNameAddr;
  649. return(STATUS_SUCCESS);
  650. }
  651. //
  652. // Check if Local Hash table
  653. //
  654. if (pHashTable == NbtConfig.pLocalHashTbl)
  655. {
  656. // In the local hash table case the scope is the same for all
  657. // names on the node and it is stored in the NbtConfig structure
  658. pScopeTbl = NbtConfig.pScope;
  659. uNameSize = NbtConfig.ScopeLength;
  660. }
  661. //
  662. // This is a Remote Hash table lookup
  663. //
  664. else if (pNameAddr->pScope)
  665. {
  666. pScopeTbl = &pNameAddr->pScope->Name[0];
  667. uNameSize = pNameAddr->pScope->ulScopeLength;
  668. }
  669. //
  670. // Remote Hash table entry with NULL scope
  671. // so if passed in scope is also Null, we have a match
  672. //
  673. else if (!uInScopeLength)
  674. {
  675. *pNameAddress = pNameAddr;
  676. return(STATUS_SUCCESS);
  677. }
  678. else
  679. {
  680. //
  681. // Hash table scope length is 0 != uInScopeLength
  682. // ==> No match!
  683. //
  684. continue;
  685. }
  686. //
  687. // strncmp will terminate at the first non-matching byte
  688. // or when it has matched uNameSize bytes
  689. //
  690. if (0 == strncmp (pScope, pScopeTbl, uNameSize))
  691. {
  692. // the scopes match so return
  693. *pNameAddress = pNameAddr;
  694. return(STATUS_SUCCESS);
  695. }
  696. } // end of matching name found
  697. }
  698. return(STATUS_UNSUCCESSFUL);
  699. }