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.

2428 lines
70 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. cache.c
  5. Abstract:
  6. This module contains the name cache routines for the Netbios
  7. module of the ISN transport.
  8. Author:
  9. Adam Barr (adamba) 20-December-1993
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE,CreateNetbiosCacheTable)
  18. #endif
  19. #ifdef RASAUTODIAL
  20. #include <acd.h>
  21. #include <acdapi.h>
  22. extern BOOLEAN fAcdLoadedG;
  23. extern ACD_DRIVER AcdDriverG;
  24. BOOLEAN
  25. NbiAttemptAutoDial(
  26. IN PDEVICE pDevice,
  27. IN PCONNECTION pConnection,
  28. IN ULONG ulFlags,
  29. IN ACD_CONNECT_CALLBACK pProc,
  30. IN PREQUEST pRequest
  31. );
  32. VOID
  33. NbiRetryTdiConnect(
  34. IN BOOLEAN fSuccess,
  35. IN PVOID *pArgs
  36. );
  37. #endif // RASAUTODIAL
  38. //
  39. // We should change to monitor add name packets better,
  40. // so if we get an add for a different place we attempt to determine
  41. // if it is real or bogus and update if possible.
  42. //
  43. NTSTATUS
  44. CacheFindName(
  45. IN PDEVICE Device,
  46. IN FIND_NAME_TYPE Type,
  47. IN PUCHAR RemoteName OPTIONAL,
  48. OUT PNETBIOS_CACHE * CacheName
  49. )
  50. /*++
  51. Routine Description:
  52. This routine looks up a particular remote name in the
  53. Netbios name cache. If it cannot find it, a find name
  54. request is queued up.
  55. THIS REQUEST IS CALLED WITH THE DEVICE LOCK HELD AND
  56. RETURNS WITH IT HELD.
  57. Arguments:
  58. Device - The netbios device.
  59. Type - Defines the type. The effect this has is:
  60. FindNameConnect - On connects we will ignore an existing
  61. cache entry if it got no response before.
  62. FindNameNetbiosFindName - For these we ignore an existing
  63. cache entry if it is for a group name -- this is
  64. because the find name wants the address of every
  65. machine, not just the network list.
  66. FindNameOther - Normal handling is done.
  67. RemoteName - The name to be discovered -- will be NULL if it
  68. is the broadcast address.
  69. CacheName - Returns the cache entry that was discovered.
  70. Return Value:
  71. None.
  72. --*/
  73. {
  74. PLIST_ENTRY p;
  75. PSINGLE_LIST_ENTRY s;
  76. PNETBIOS_CACHE FoundCacheName;
  77. PNB_SEND_RESERVED Reserved;
  78. PUCHAR RealRemoteName; // RemoteName or NetbiosBroadcastName
  79. //
  80. // First scan the netbios name cache to see if we know
  81. // about this remote.
  82. //
  83. if (RemoteName) {
  84. RealRemoteName = RemoteName;
  85. } else {
  86. RealRemoteName = NetbiosBroadcastName;
  87. }
  88. if ( FindInNetbiosCacheTable ( Device->NameCache,
  89. RealRemoteName,
  90. &FoundCacheName ) == STATUS_SUCCESS ) {
  91. //
  92. // If this is a netbios find name, we only can use unique
  93. // names in the cache; for the group ones we need to requery
  94. // because the cache only lists networks, not individual machines.
  95. // For connect requests, if we find an empty cache entry we
  96. // remove it and requery.
  97. //
  98. if ( FoundCacheName->Unique || (Type != FindNameNetbiosFindName) ) {
  99. if (FoundCacheName->NetworksUsed > 0) {
  100. *CacheName = FoundCacheName;
  101. NB_DEBUG2 (CACHE, ("Found cache name <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
  102. return STATUS_SUCCESS;
  103. } else {
  104. if (Type != FindNameConnect) {
  105. if (FoundCacheName->FailedOnDownWan) {
  106. NB_DEBUG2 (CACHE, ("Found cache name, but down wan <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
  107. return STATUS_DEVICE_DOES_NOT_EXIST;
  108. } else {
  109. NB_DEBUG2 (CACHE, ("Found cache name, but no nets <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
  110. return STATUS_BAD_NETWORK_PATH;
  111. }
  112. } else {
  113. //
  114. // This is a connect and the current cache entry
  115. // has zero names; delete it.
  116. //
  117. RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
  118. CTEAssert (FoundCacheName->ReferenceCount == 1);
  119. if (--FoundCacheName->ReferenceCount == 0) {
  120. NB_DEBUG2 (CACHE, ("Free unneeded empty cache entry %lx\n", FoundCacheName));
  121. NbiFreeMemory(
  122. FoundCacheName,
  123. sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  124. MEMORY_CACHE,
  125. "Free due to replacement");
  126. }
  127. }
  128. }
  129. }
  130. }
  131. //
  132. // There was no suitable cache entry for this network, first see
  133. // if there is one pending.
  134. //
  135. for (p = Device->WaitingFindNames.Flink;
  136. p != &Device->WaitingFindNames;
  137. p = p->Flink) {
  138. Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
  139. //
  140. // For this purpose we ignore a packet if a route
  141. // has been found and it was for a unique name. This
  142. // is because the cache information has already been
  143. // inserted for this name. Otherwise if the name has
  144. // since been deleted from the cache, the request
  145. // that is looking for this name will starve because
  146. // FindNameTimeout will just destroy the packet.
  147. //
  148. if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
  149. continue;
  150. }
  151. if (RtlEqualMemory(
  152. Reserved->u.SR_FN.NetbiosName,
  153. RealRemoteName, 16)) {
  154. NB_DEBUG2 (CACHE, ("Cache name already pending <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
  155. //
  156. // There is already one pending. If it is for a group
  157. // name and this is a netbios find name, we make sure
  158. // the retry count is such that at least one more
  159. // query will be sent, so the netbios find name
  160. // buffer can be filled with the responses from this.
  161. //
  162. if ((Type == FindNameNetbiosFindName) &&
  163. (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) &&
  164. (Reserved->u.SR_FN.RetryCount == Device->BroadcastCount)) {
  165. --Reserved->u.SR_FN.RetryCount;
  166. }
  167. return STATUS_PENDING;
  168. }
  169. }
  170. s = NbiPopSendPacket(Device, TRUE);
  171. if (s == NULL) {
  172. NB_DEBUG (CACHE, ("Couldn't get packet to find <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
  173. return STATUS_INSUFFICIENT_RESOURCES;
  174. }
  175. Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
  176. //
  177. // We have the packet, fill it in for this request.
  178. //
  179. CTEAssert (Reserved->SendInProgress == FALSE);
  180. Reserved->SendInProgress = FALSE;
  181. Reserved->Type = SEND_TYPE_FIND_NAME;
  182. RtlCopyMemory (Reserved->u.SR_FN.NetbiosName, RealRemoteName, 16);
  183. Reserved->u.SR_FN.StatusAndSentOnUpLine = FNStatusNoResponse; // SentOnUpLine is FALSE
  184. Reserved->u.SR_FN.RetryCount = 0;
  185. Reserved->u.SR_FN.NewCache = NULL;
  186. Reserved->u.SR_FN.SendTime = Device->FindNameTime;
  187. #if !defined(_PNP_POWER)
  188. Reserved->u.SR_FN.CurrentNicId = 1;
  189. (VOID)(*Device->Bind.QueryHandler)( // Check return code ?
  190. IPX_QUERY_MAX_TYPE_20_NIC_ID,
  191. (USHORT)0,
  192. &Reserved->u.SR_FN.MaximumNicId,
  193. sizeof(USHORT),
  194. NULL);
  195. if (Reserved->u.SR_FN.MaximumNicId == 0) {
  196. Reserved->u.SR_FN.MaximumNicId = 1; // code assumes at least one
  197. }
  198. #endif !_PNP_POWER
  199. NB_DEBUG2 (CACHE, ("Queued FIND_NAME %lx for <%.16s>\n",
  200. Reserved, RemoteName ? RemoteName : "<broadcast>"));
  201. InsertHeadList(
  202. &Device->WaitingFindNames,
  203. &Reserved->WaitLinkage);
  204. ++Device->FindNamePacketCount;
  205. if (!Device->FindNameTimerActive) {
  206. Device->FindNameTimerActive = TRUE;
  207. NbiReferenceDevice (Device, DREF_FN_TIMER);
  208. CTEStartTimer(
  209. &Device->FindNameTimer,
  210. 1, // 1 ms, i.e. expire immediately
  211. FindNameTimeout,
  212. (PVOID)Device);
  213. }
  214. NbiReferenceDevice (Device, DREF_FIND_NAME);
  215. return STATUS_PENDING;
  216. } /* CacheFindName */
  217. VOID
  218. FindNameTimeout(
  219. CTEEvent * Event,
  220. PVOID Context
  221. )
  222. /*++
  223. Routine Description:
  224. This routine is called when the find name timer expires.
  225. It is called every FIND_NAME_GRANULARITY milliseconds unless there
  226. is nothing to do.
  227. Arguments:
  228. Event - The event used to queue the timer.
  229. Context - The context, which is the device pointer.
  230. Return Value:
  231. None.
  232. --*/
  233. {
  234. PDEVICE Device = (PDEVICE)Context;
  235. PLIST_ENTRY p, q;
  236. PNB_SEND_RESERVED Reserved;
  237. PNDIS_PACKET Packet;
  238. NB_CONNECTIONLESS UNALIGNED * Header;
  239. PNETBIOS_CACHE FoundCacheName;
  240. NDIS_STATUS NdisStatus;
  241. #if !defined(_PNP_POWER)
  242. static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
  243. #endif !_PNP_POWER
  244. NB_DEFINE_LOCK_HANDLE (LockHandle)
  245. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  246. ++Device->FindNameTime;
  247. if (Device->FindNamePacketCount == 0) {
  248. NB_DEBUG2 (CACHE, ("FindNameTimeout exiting\n"));
  249. Device->FindNameTimerActive = FALSE;
  250. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  251. NbiDereferenceDevice (Device, DREF_FN_TIMER);
  252. return;
  253. }
  254. //
  255. // Check what is on the queue; this is set up as a
  256. // loop but in fact it rarely does (under no
  257. // circumstances can we send more than one packet
  258. // each time this function executes).
  259. //
  260. while (TRUE) {
  261. p = Device->WaitingFindNames.Flink;
  262. if (p == &Device->WaitingFindNames) {
  263. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  264. break;
  265. }
  266. Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
  267. if (Reserved->SendInProgress) {
  268. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  269. break;
  270. }
  271. if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
  272. //
  273. // This was a find name for a unique name which got a
  274. // response but was not freed at the time (because
  275. // SendInProgress was still TRUE) so we free it now.
  276. //
  277. (VOID)RemoveHeadList (&Device->WaitingFindNames);
  278. ExInterlockedPushEntrySList(
  279. &Device->SendPacketList,
  280. &Reserved->PoolLinkage,
  281. &NbiGlobalPoolInterlock);
  282. --Device->FindNamePacketCount;
  283. //
  284. // It is OK to do this with the lock held because
  285. // it won't be the last one (we have the RIP_TIMER ref).
  286. //
  287. NbiDereferenceDevice (Device, DREF_FIND_NAME);
  288. continue;
  289. }
  290. if (((SHORT) (Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
  291. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  292. break;
  293. }
  294. (VOID)RemoveHeadList (&Device->WaitingFindNames);
  295. //
  296. // Increment the counter and see if we have sent
  297. // all the frames we need to (we will age out
  298. // here if we got no response for a unique query,
  299. // or if we are doing a global name or broadcast
  300. // search). We also kill the query right now if
  301. // we have not found anything but down wan lines
  302. // to send it on.
  303. //
  304. if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
  305. ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
  306. #if DBG
  307. if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
  308. NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
  309. } else {
  310. NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
  311. }
  312. #endif
  313. //
  314. // This packet is stale, clean it up and continue.
  315. //
  316. if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
  317. CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
  318. //
  319. // If this was a group name and we have a new
  320. // cache entry that we have been building for it,
  321. // then insert that in the queue and use it
  322. // to succeed any pending connects. Because
  323. // netbios find name requests can cause cache
  324. // requests for group names to be queued even
  325. // if we already have on in the database, we
  326. // first scan for old ones and remove them.
  327. //
  328. if ( FindInNetbiosCacheTable( Device->NameCache,
  329. Reserved->u.SR_FN.NetbiosName,
  330. &FoundCacheName ) == STATUS_SUCCESS ) {
  331. NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
  332. RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
  333. if (--FoundCacheName->ReferenceCount == 0) {
  334. NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
  335. NbiFreeMemory(
  336. FoundCacheName,
  337. sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  338. MEMORY_CACHE,
  339. "Free due to replacement");
  340. }
  341. }
  342. Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
  343. InsertInNetbiosCacheTable(
  344. Device->NameCache,
  345. Reserved->u.SR_FN.NewCache);
  346. //
  347. // Reference it for the moment since CacheHandlePending
  348. // uses it after releasing the lock. CacheHandlePending
  349. // will dereference it.
  350. //
  351. ++Reserved->u.SR_FN.NewCache->ReferenceCount;
  352. //
  353. // This call releases the locks
  354. //
  355. CacheHandlePending(
  356. Device,
  357. Reserved->u.SR_FN.NetbiosName,
  358. NetbiosNameFound,
  359. Reserved->u.SR_FN.NewCache
  360. NB_LOCK_HANDLE_ARG(LockHandle));
  361. } else {
  362. CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
  363. //
  364. // Allocate an empty cache entry to record the
  365. // fact that we could not find this name, unless
  366. // there is already an entry for this name.
  367. //
  368. if ( FindInNetbiosCacheTable( Device->NameCache,
  369. Reserved->u.SR_FN.NetbiosName,
  370. &FoundCacheName ) == STATUS_SUCCESS ) {
  371. NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%16.16s>\n", FoundCacheName->NetbiosName));
  372. } else {
  373. PNETBIOS_CACHE EmptyCache;
  374. //
  375. // Nothing found.
  376. //
  377. EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
  378. if (EmptyCache != NULL) {
  379. RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
  380. NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
  381. EmptyCache, Reserved->u.SR_FN.NetbiosName));
  382. RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
  383. EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
  384. EmptyCache->ReferenceCount = 1;
  385. EmptyCache->NetworksAllocated = 1;
  386. EmptyCache->TimeStamp = Device->CacheTimeStamp;
  387. EmptyCache->NetworksUsed = 0;
  388. EmptyCache->FailedOnDownWan = (BOOLEAN)
  389. !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
  390. InsertInNetbiosCacheTable (
  391. Device->NameCache,
  392. EmptyCache);
  393. }
  394. }
  395. //
  396. // Fail all datagrams, etc. that were waiting for
  397. // this route. This call releases the lock.
  398. //
  399. CacheHandlePending(
  400. Device,
  401. Reserved->u.SR_FN.NetbiosName,
  402. NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
  403. NetbiosNameNotFoundNormal :
  404. NetbiosNameNotFoundWanDown,
  405. NULL
  406. NB_LOCK_HANDLE_ARG(LockHandle));
  407. }
  408. ExInterlockedPushEntrySList(
  409. &Device->SendPacketList,
  410. &Reserved->PoolLinkage,
  411. &NbiGlobalPoolInterlock);
  412. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  413. --Device->FindNamePacketCount;
  414. NbiDereferenceDevice (Device, DREF_FIND_NAME);
  415. continue;
  416. }
  417. //
  418. // Send the packet out again. We first set the time so
  419. // it won't be sent again until the appropriate timeout.
  420. //
  421. Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
  422. InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
  423. CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
  424. CTEAssert (!Reserved->SendInProgress);
  425. Reserved->SendInProgress = TRUE;
  426. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  427. //
  428. // If this is the first retry, we need to initialize the packet
  429. //
  430. if ( Reserved->u.SR_FN.RetryCount == 1 ) {
  431. //
  432. // Fill in the IPX header -- the default header has the broadcast
  433. // address on net 0 as the destination IPX address, which is
  434. // what we want.
  435. //
  436. Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
  437. RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
  438. Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
  439. Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
  440. Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
  441. //
  442. // Now fill in the Netbios header.
  443. //
  444. RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
  445. Header->NameFrame.ConnectionControlFlag = 0x00;
  446. // Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
  447. Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
  448. Header->NameFrame.NameTypeFlag = 0x00;
  449. RtlCopyMemory(
  450. Header->NameFrame.Name,
  451. Reserved->u.SR_FN.NetbiosName,
  452. 16);
  453. }
  454. //
  455. // Now submit the packet to IPX.
  456. //
  457. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  458. NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx\n", Reserved));
  459. NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
  460. sizeof(NB_NAME_FRAME));
  461. if ((NdisStatus =
  462. (*Device->Bind.SendHandler)(
  463. &BroadcastTarget,
  464. Packet,
  465. sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
  466. sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
  467. NbiSendComplete(
  468. Packet,
  469. NdisStatus);
  470. }
  471. break;
  472. }
  473. //
  474. // Since we did something this time, we restart the timer.
  475. //
  476. CTEStartTimer(
  477. &Device->FindNameTimer,
  478. FIND_NAME_GRANULARITY,
  479. FindNameTimeout,
  480. (PVOID)Device);
  481. } /* FindNameTimeout */
  482. VOID
  483. CacheHandlePending(
  484. IN PDEVICE Device,
  485. IN PUCHAR RemoteName,
  486. IN NETBIOS_NAME_RESULT Result,
  487. IN PNETBIOS_CACHE CacheName OPTIONAL
  488. IN NB_LOCK_HANDLE_PARAM(LockHandle)
  489. )
  490. /*++
  491. Routine Description:
  492. This routine cleans up pending datagrams and connects
  493. that were waiting for a route to be discovered to a
  494. given Netbios NAME. THIS ROUTINE IS CALLED WITH
  495. DEVICE->LOCK ACQUIRED AND RETURNS WITH IT RELEASED.
  496. Arguments:
  497. Device - The device.
  498. RemoteName - The netbios name that was being searched for.
  499. Result - Indicates if the name was found, or not found due
  500. to no response or wan lines being down.
  501. CacheName - If Result is NetbiosNameFound, the cache entry for this name.
  502. This entry has been referenced and this routine will deref it.
  503. LockHandle - The handle used to acquire the lock.
  504. Return Value:
  505. None.
  506. --*/
  507. {
  508. LIST_ENTRY DatagramList;
  509. LIST_ENTRY ConnectList;
  510. LIST_ENTRY AdapterStatusList;
  511. LIST_ENTRY NetbiosFindNameList;
  512. PNB_SEND_RESERVED Reserved;
  513. PNDIS_PACKET Packet;
  514. PLIST_ENTRY p;
  515. PREQUEST ConnectRequest, DatagramRequest, AdapterStatusRequest, NetbiosFindNameRequest;
  516. PCONNECTION Connection;
  517. PADDRESS_FILE AddressFile;
  518. TDI_ADDRESS_NETBIOS * RemoteAddress;
  519. CTELockHandle CancelLH;
  520. NB_DEFINE_LOCK_HANDLE (LockHandle1)
  521. InitializeListHead (&DatagramList);
  522. InitializeListHead (&ConnectList);
  523. InitializeListHead (&AdapterStatusList);
  524. InitializeListHead (&NetbiosFindNameList);
  525. //
  526. // Put all connect requests on ConnectList. They will
  527. // be continued or failed later.
  528. //
  529. p = Device->WaitingConnects.Flink;
  530. while (p != &Device->WaitingConnects) {
  531. ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
  532. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
  533. p = p->Flink;
  534. if (RtlEqualMemory (Connection->RemoteName, RemoteName, 16)) {
  535. RemoveEntryList (REQUEST_LINKAGE(ConnectRequest));
  536. InsertTailList (&ConnectList, REQUEST_LINKAGE(ConnectRequest));
  537. Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
  538. }
  539. }
  540. //
  541. // Put all the datagrams on Datagram list. They will be
  542. // sent or failed later.
  543. //
  544. p = Device->WaitingDatagrams.Flink;
  545. while (p != &Device->WaitingDatagrams) {
  546. Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
  547. p = p->Flink;
  548. //
  549. // Check differently based on whether we were looking for
  550. // the broadcast address or not.
  551. //
  552. if (Reserved->u.SR_DG.RemoteName == (PVOID)-1) {
  553. if (!RtlEqualMemory (RemoteName, NetbiosBroadcastName, 16)) {
  554. continue;
  555. }
  556. } else {
  557. if (!RtlEqualMemory (RemoteName, Reserved->u.SR_DG.RemoteName->NetbiosName, 16)) {
  558. continue;
  559. }
  560. }
  561. RemoveEntryList (&Reserved->WaitLinkage);
  562. InsertTailList (&DatagramList, &Reserved->WaitLinkage);
  563. //
  564. // Reference this here with the lock held.
  565. //
  566. if (Result == NetbiosNameFound) {
  567. ++CacheName->ReferenceCount;
  568. }
  569. }
  570. //
  571. // Put all the adapter status requests on AdapterStatus
  572. // list. They will be sent or failed later.
  573. //
  574. p = Device->WaitingAdapterStatus.Flink;
  575. while (p != &Device->WaitingAdapterStatus) {
  576. AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
  577. p = p->Flink;
  578. RemoteAddress = (TDI_ADDRESS_NETBIOS *)REQUEST_INFORMATION(AdapterStatusRequest);
  579. if (!RtlEqualMemory(
  580. RemoteName,
  581. RemoteAddress->NetbiosName,
  582. 16)) {
  583. continue;
  584. }
  585. RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
  586. InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
  587. //
  588. // Reference this here with the lock held.
  589. //
  590. if (Result == NetbiosNameFound) {
  591. ++CacheName->ReferenceCount;
  592. }
  593. }
  594. //
  595. // Put all the netbios find name requests on NetbiosFindName
  596. // list. They will be completed later.
  597. //
  598. p = Device->WaitingNetbiosFindName.Flink;
  599. while (p != &Device->WaitingNetbiosFindName) {
  600. NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
  601. p = p->Flink;
  602. RemoteAddress = (TDI_ADDRESS_NETBIOS *)REQUEST_INFORMATION(NetbiosFindNameRequest);
  603. if (!RtlEqualMemory(
  604. RemoteName,
  605. RemoteAddress->NetbiosName,
  606. 16)) {
  607. continue;
  608. }
  609. RemoveEntryList (REQUEST_LINKAGE(NetbiosFindNameRequest));
  610. InsertTailList (&NetbiosFindNameList, REQUEST_LINKAGE(NetbiosFindNameRequest));
  611. }
  612. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  613. //
  614. // Now that the lock is free, process all the packets on
  615. // the various lists.
  616. //
  617. for (p = ConnectList.Flink; p != &ConnectList; ) {
  618. ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
  619. p = p->Flink;
  620. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
  621. NB_GET_CANCEL_LOCK( &CancelLH );
  622. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
  623. if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
  624. (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
  625. if (Result == NetbiosNameFound) {
  626. NB_DEBUG2 (CONNECTION, ("Found queued connect %lx on %lx\n", ConnectRequest, Connection));
  627. //
  628. // Continue with the connection sequence.
  629. //
  630. Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
  631. }
  632. if ((Result == NetbiosNameFound) && (!ConnectRequest->Cancel)) {
  633. IoSetCancelRoutine (ConnectRequest, NbiCancelConnectWaitResponse);
  634. NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1 );
  635. NB_FREE_CANCEL_LOCK ( CancelLH );
  636. Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
  637. RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
  638. NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
  639. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  640. *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
  641. RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
  642. Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
  643. Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
  644. //
  645. // When this completes, we will send the session init.
  646. // We don't call it if the client is for network 0,
  647. // instead just fake as if no route could be found
  648. // and we will use the local target we got here.
  649. //
  650. if (CacheName->FirstResponse.NetworkAddress != 0) {
  651. (*Device->Bind.FindRouteHandler) (&Connection->FindRouteRequest);
  652. } else {
  653. NbiFindRouteComplete( &Connection->FindRouteRequest, FALSE);
  654. }
  655. } else {
  656. BOOLEAN bAutodialAttempt = FALSE;
  657. if (ConnectRequest->Cancel) {
  658. NB_DEBUG2 (CONNECTION, ("Cancelling connect %lx on %lx\n", ConnectRequest, Connection));
  659. }
  660. else
  661. {
  662. NB_DEBUG2 (CONNECTION, ("Timing out connect %lx on %lx\n", ConnectRequest, Connection));
  663. }
  664. ASSERT (Connection->ConnectRequest == ConnectRequest);
  665. #ifdef RASAUTODIAL
  666. if (fAcdLoadedG) {
  667. CTELockHandle adirql;
  668. BOOLEAN fEnabled;
  669. //
  670. // See if the automatic connection driver knows
  671. // about this address before we search the
  672. // network. If it does, we return STATUS_PENDING,
  673. // and we will come back here via NbfRetryTdiConnect().
  674. //
  675. CTEGetLock(&AcdDriverG.SpinLock, &adirql);
  676. fEnabled = AcdDriverG.fEnabled;
  677. CTEFreeLock(&AcdDriverG.SpinLock, adirql);
  678. if (fEnabled && NbiAttemptAutoDial(
  679. Device,
  680. Connection,
  681. 0,
  682. NbiRetryTdiConnect,
  683. ConnectRequest))
  684. {
  685. NB_SYNC_FREE_LOCK(&Connection->Lock, LockHandle1);
  686. NB_FREE_CANCEL_LOCK(CancelLH);
  687. bAutodialAttempt = TRUE;
  688. }
  689. }
  690. #endif // RASAUTODIAL
  691. if (!bAutodialAttempt) {
  692. Connection->ConnectRequest = NULL;
  693. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  694. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  695. IoSetCancelRoutine( ConnectRequest, (PDRIVER_CANCEL)NULL );
  696. NB_FREE_CANCEL_LOCK( CancelLH );
  697. REQUEST_STATUS(ConnectRequest) = STATUS_BAD_NETWORK_PATH;
  698. NbiCompleteRequest(ConnectRequest);
  699. NbiFreeRequest (Device, ConnectRequest);
  700. }
  701. NbiDereferenceConnection (Connection, CREF_CONNECT);
  702. }
  703. } else {
  704. CTEAssert (0); // What happens to the IRP? Who completes it?
  705. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  706. NB_FREE_CANCEL_LOCK( CancelLH );
  707. }
  708. NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
  709. }
  710. for (p = DatagramList.Flink; p != &DatagramList; ) {
  711. Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
  712. p = p->Flink;
  713. if (Result == NetbiosNameFound) {
  714. NB_DEBUG2 (DATAGRAM, ("Found queued datagram %lx on %lx\n", Reserved->u.SR_DG.DatagramRequest, Reserved->u.SR_DG.AddressFile));
  715. Reserved->u.SR_DG.Cache = CacheName;
  716. Reserved->u.SR_DG.CurrentNetwork = 0;
  717. //
  718. // CacheName was referenced above.
  719. //
  720. Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
  721. if ( REQUEST_NDIS_BUFFER( Reserved->u.SR_DG.DatagramRequest )) {
  722. NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Reserved->u.SR_DG.DatagramRequest));
  723. }
  724. NbiTransmitDatagram (Reserved);
  725. } else {
  726. //
  727. // Should we send it once as a broadcast
  728. // on net 0, just in case??
  729. //
  730. AddressFile = Reserved->u.SR_DG.AddressFile;
  731. DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
  732. NB_DEBUG2 (DATAGRAM, ("Timing out datagram %lx on %lx\n", DatagramRequest, AddressFile));
  733. //
  734. // If the failure was due to a down wan line indicate
  735. // that, otherwise return success (so the browser won't
  736. // confuse this with a down wan line).
  737. //
  738. if (Result == NetbiosNameNotFoundWanDown) {
  739. REQUEST_STATUS(DatagramRequest) = STATUS_DEVICE_DOES_NOT_EXIST;
  740. } else {
  741. REQUEST_STATUS(DatagramRequest) = STATUS_BAD_NETWORK_PATH;
  742. }
  743. REQUEST_INFORMATION(DatagramRequest) = 0;
  744. NbiCompleteRequest(DatagramRequest);
  745. NbiFreeRequest (Device, DatagramRequest);
  746. NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
  747. ExInterlockedPushEntrySList(
  748. &Device->SendPacketList,
  749. &Reserved->PoolLinkage,
  750. &NbiGlobalPoolInterlock);
  751. }
  752. }
  753. for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
  754. AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
  755. p = p->Flink;
  756. if (Result == NetbiosNameFound) {
  757. NB_DEBUG2 (QUERY, ("Found queued AdapterStatus %lx\n", AdapterStatusRequest));
  758. //
  759. // Continue with the AdapterStatus sequence. We put
  760. // it in ActiveAdapterStatus, it will either get
  761. // completed when a response is received or timed
  762. // out by the long timeout.
  763. //
  764. REQUEST_STATUSPTR(AdapterStatusRequest) = (PVOID)CacheName;
  765. //
  766. // CacheName was referenced above.
  767. //
  768. REQUEST_INFORMATION (AdapterStatusRequest) = 0;
  769. NB_INSERT_TAIL_LIST(
  770. &Device->ActiveAdapterStatus,
  771. REQUEST_LINKAGE (AdapterStatusRequest),
  772. &Device->Lock);
  773. NbiSendStatusQuery (AdapterStatusRequest);
  774. } else {
  775. NB_DEBUG2 (QUERY, ("Timing out AdapterStatus %lx\n", AdapterStatusRequest));
  776. REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
  777. NbiCompleteRequest(AdapterStatusRequest);
  778. NbiFreeRequest (Device, AdapterStatusRequest);
  779. NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
  780. }
  781. }
  782. for (p = NetbiosFindNameList.Flink; p != &NetbiosFindNameList; ) {
  783. NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
  784. p = p->Flink;
  785. //
  786. // In fact there is not much difference between success or
  787. // failure, since in the successful case the information
  788. // will already have been written to the buffer. Just
  789. // complete the request with the appropriate status,
  790. // which will already be stored in the request.
  791. //
  792. if (Result == NetbiosNameFound) {
  793. if (CacheName->Unique) {
  794. NB_DEBUG2 (QUERY, ("Found queued unique NetbiosFindName %lx\n", NetbiosFindNameRequest));
  795. } else {
  796. NB_DEBUG2 (QUERY, ("Found queued group NetbiosFindName %lx\n", NetbiosFindNameRequest));
  797. }
  798. } else {
  799. CTEAssert (REQUEST_STATUS(NetbiosFindNameRequest) == STATUS_IO_TIMEOUT);
  800. NB_DEBUG2 (QUERY, ("Timed out NetbiosFindName %lx\n", NetbiosFindNameRequest));
  801. }
  802. //
  803. // This sets REQUEST_INFORMATION(Request) to the correct value.
  804. //
  805. NbiSetNetbiosFindNameInformation (NetbiosFindNameRequest);
  806. NbiCompleteRequest(NetbiosFindNameRequest);
  807. NbiFreeRequest (Device, NetbiosFindNameRequest);
  808. NbiDereferenceDevice (Device, DREF_NB_FIND_NAME);
  809. }
  810. //
  811. // We referenced this temporarily so we could use it in here,
  812. // deref and check if we need to delete it.
  813. //
  814. if (Result == NetbiosNameFound) {
  815. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
  816. if (--CacheName->ReferenceCount == 0) {
  817. NB_DEBUG2 (CACHE, ("Free newly allocated cache entry %lx\n", CacheName));
  818. NbiFreeMemory(
  819. CacheName,
  820. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  821. MEMORY_CACHE,
  822. "Free in CacheHandlePending");
  823. }
  824. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
  825. }
  826. } /* CacheHandlePending */
  827. VOID
  828. NbiProcessNameRecognized(
  829. IN PIPX_LOCAL_TARGET RemoteAddress,
  830. IN ULONG MacOptions,
  831. IN PUCHAR PacketBuffer,
  832. IN UINT PacketSize
  833. )
  834. /*++
  835. Routine Description:
  836. This routine handles NB_CMD_NAME_RECOGNIZED frames.
  837. Arguments:
  838. RemoteAddress - The local target this packet was received from.
  839. MacOptions - The MAC options for the underlying NDIS binding.
  840. LookaheadBuffer - The packet data, starting at the IPX
  841. header.
  842. PacketSize - The total length of the packet, starting at the
  843. IPX header.
  844. Return Value:
  845. None.
  846. --*/
  847. {
  848. PLIST_ENTRY p;
  849. PDEVICE Device = NbiDevice;
  850. PNETBIOS_CACHE NameCache;
  851. PREQUEST NetbiosFindNameRequest;
  852. PNB_SEND_RESERVED Reserved;
  853. TDI_ADDRESS_NETBIOS * RemoteNetbiosAddress;
  854. NB_CONNECTIONLESS UNALIGNED * Connectionless =
  855. (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
  856. NB_DEFINE_LOCK_HANDLE(LockHandle)
  857. #if 0
  858. //
  859. // We should handle responses from network 0
  860. // differently -- if they are for a group name, we should
  861. // keep them around but only until we get a non-zero
  862. // response from the same card.
  863. //
  864. if (*(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork) == 0) {
  865. return;
  866. }
  867. #endif
  868. //
  869. // We need to scan our queue of pending find name packets
  870. // to see if someone is waiting for this name.
  871. //
  872. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  873. for (p = Device->WaitingFindNames.Flink;
  874. p != &Device->WaitingFindNames;
  875. p = p->Flink) {
  876. Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
  877. //
  878. // Find names which have already found unique names are
  879. // "dead", waiting for FindNameTimeout to remove them,
  880. // and should be ignored when scanning the list.
  881. //
  882. if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
  883. continue;
  884. }
  885. if (RtlEqualMemory (Reserved->u.SR_FN.NetbiosName, Connectionless->NameFrame.Name, 16)) {
  886. break;
  887. }
  888. }
  889. if (p == &Device->WaitingFindNames)
  890. {
  891. if ((FindInNetbiosCacheTable (Device->NameCache,
  892. Connectionless->NameFrame.Name,
  893. &NameCache ) == STATUS_SUCCESS) &&
  894. (NameCache->NetworksUsed == 0))
  895. {
  896. //
  897. // Update our information about this network if needed.
  898. //
  899. NameCache->Unique = (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0);
  900. if (RtlEqualMemory (Connectionless->NameFrame.Name, NetbiosBroadcastName, 16))
  901. {
  902. NameCache->Unique = FALSE;
  903. }
  904. RtlCopyMemory (&NameCache->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
  905. NameCache->NetworksUsed = 1;
  906. NameCache->Networks[0].Network = *(UNALIGNED ULONG*)(Connectionless->IpxHeader.SourceNetwork);
  907. //
  908. // If this packet was not routed to us and is for a group name,
  909. // rather than use whatever local target it happened to come
  910. // from we set it up so that it is broadcast on that net.
  911. //
  912. if ((RtlEqualMemory (RemoteAddress->MacAddress, Connectionless->IpxHeader.SourceNode, 6)) &&
  913. (!NameCache->Unique))
  914. {
  915. NameCache->Networks[0].LocalTarget.NicHandle = RemoteAddress->NicHandle;
  916. RtlCopyMemory (NameCache->Networks[0].LocalTarget.MacAddress, BroadcastAddress, 6);
  917. RtlCopyMemory (NameCache->FirstResponse.NodeAddress, BroadcastAddress, 6);
  918. }
  919. else
  920. {
  921. NameCache->Networks[0].LocalTarget = *RemoteAddress;
  922. }
  923. }
  924. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  925. return;
  926. }
  927. //
  928. // Scan for any netbios find name requests on the queue, and
  929. // inform them about this remote. We need to do this on every
  930. // response because group names need every computer recorded,
  931. // but the normal cache only includes one entry per network.
  932. //
  933. for (p = Device->WaitingNetbiosFindName.Flink;
  934. p != &Device->WaitingNetbiosFindName;
  935. p = p->Flink) {
  936. NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
  937. RemoteNetbiosAddress = (TDI_ADDRESS_NETBIOS *)REQUEST_INFORMATION(NetbiosFindNameRequest);
  938. if (!RtlEqualMemory(
  939. Connectionless->NameFrame.Name,
  940. RemoteNetbiosAddress->NetbiosName,
  941. 16)) {
  942. continue;
  943. }
  944. //
  945. // This will update the request status if needed.
  946. //
  947. NbiUpdateNetbiosFindName(
  948. NetbiosFindNameRequest,
  949. #if defined(_PNP_POWER)
  950. &RemoteAddress->NicHandle,
  951. #else
  952. RemoteAddress->NicId,
  953. #endif _PNP_POWER
  954. (TDI_ADDRESS_IPX UNALIGNED *)Connectionless->IpxHeader.SourceNetwork,
  955. (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0));
  956. }
  957. //
  958. // See what is up with this pending find name packet.
  959. //
  960. if (Reserved->u.SR_FN.NewCache == NULL) {
  961. //
  962. // This is the first response we have received, so we
  963. // allocate the initial entry with room for a single
  964. // entry.
  965. //
  966. NameCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
  967. if (NameCache == NULL) {
  968. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  969. return;
  970. }
  971. NB_DEBUG2 (CACHE, ("Alloc new cache %lx for <%.16s>, net %lx\n",
  972. NameCache, Reserved->u.SR_FN.NetbiosName,
  973. *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork)));
  974. RtlCopyMemory (NameCache->NetbiosName, Connectionless->NameFrame.Name, 16);
  975. NameCache->Unique = (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0);
  976. NameCache->ReferenceCount = 1;
  977. RtlCopyMemory (&NameCache->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
  978. NameCache->NetworksAllocated = 1;
  979. NameCache->NetworksUsed = 1;
  980. NameCache->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
  981. if (RtlEqualMemory (Connectionless->NameFrame.Name, NetbiosBroadcastName, 16)) {
  982. NB_SET_SR_FN_STATUS (Reserved, FNStatusResponseGroup);
  983. NameCache->Unique = FALSE;
  984. } else {
  985. NB_SET_SR_FN_STATUS(
  986. Reserved,
  987. NameCache->Unique ? FNStatusResponseUnique : FNStatusResponseGroup);
  988. }
  989. Reserved->u.SR_FN.NewCache = NameCache;
  990. //
  991. // If this packet was not routed to us and is for a group name,
  992. // rather than use whatever local target it happened to come
  993. // from we set it up so that it is broadcast on that net.
  994. //
  995. if ((RtlEqualMemory (RemoteAddress->MacAddress, Connectionless->IpxHeader.SourceNode, 6)) &&
  996. (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup)) {
  997. #if defined(_PNP_POWER)
  998. NameCache->Networks[0].LocalTarget.NicHandle = RemoteAddress->NicHandle;
  999. #else
  1000. NameCache->Networks[0].LocalTarget.NicId = RemoteAddress->NicId;
  1001. #endif _PNP_POWER
  1002. RtlCopyMemory (NameCache->Networks[0].LocalTarget.MacAddress, BroadcastAddress, 6);
  1003. RtlCopyMemory (NameCache->FirstResponse.NodeAddress, BroadcastAddress, 6);
  1004. } else {
  1005. NameCache->Networks[0].LocalTarget = *RemoteAddress;
  1006. }
  1007. if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
  1008. //
  1009. // Complete pending requests now, since it is a unique
  1010. // name we have all the information we will get.
  1011. //
  1012. NameCache->TimeStamp = Device->CacheTimeStamp;
  1013. InsertInNetbiosCacheTable(
  1014. Device->NameCache,
  1015. NameCache);
  1016. //
  1017. // Reference it since CacheHandlePending uses it
  1018. // with the lock released. CacheHandlePending
  1019. // will dereference it.
  1020. //
  1021. ++NameCache->ReferenceCount;
  1022. //
  1023. // This call releases the lock.
  1024. //
  1025. CacheHandlePending(
  1026. Device,
  1027. Reserved->u.SR_FN.NetbiosName,
  1028. NetbiosNameFound,
  1029. NameCache
  1030. NB_LOCK_HANDLE_ARG(LockHandle));
  1031. } else {
  1032. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1033. }
  1034. } else {
  1035. //
  1036. // We already have a response to this frame.
  1037. //
  1038. if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
  1039. //
  1040. // Should we check that the response is also
  1041. // unique? Not much to do since I don't know of an
  1042. // equivalent to the netbeui NAME_IN_CONFLICT.
  1043. //
  1044. } else {
  1045. //
  1046. // This is a group name.
  1047. //
  1048. if (Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) {
  1049. //
  1050. // Update our information about this network if needed.
  1051. // This may free the existing cache and allocate a new one.
  1052. //
  1053. Reserved->u.SR_FN.NewCache =
  1054. CacheUpdateNameCache(
  1055. Reserved->u.SR_FN.NewCache,
  1056. RemoteAddress,
  1057. (TDI_ADDRESS_IPX UNALIGNED *)
  1058. Connectionless->IpxHeader.SourceNetwork,
  1059. FALSE);
  1060. } else {
  1061. //
  1062. // Hmmm... This respondent thinks it is a unique name
  1063. // but we think it is group, should we do something?
  1064. //
  1065. }
  1066. }
  1067. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1068. }
  1069. } /* NbiProcessNameRecognized */
  1070. PNETBIOS_CACHE
  1071. CacheUpdateNameCache(
  1072. IN PNETBIOS_CACHE NameCache,
  1073. IN PIPX_LOCAL_TARGET RemoteAddress,
  1074. IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
  1075. IN BOOLEAN ModifyQueue
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. This routine is called to update a netbios cache entry
  1080. with a new network, if it is does not already contain
  1081. information about the network. It is called when a frame
  1082. is received advertising the appropriate cache entry, which
  1083. is either a group name or the broadcast name.
  1084. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1085. WITH IT HELD.
  1086. Arguments:
  1087. NameCache - The name cache entry to update.
  1088. RemoteAddress - The remote address on which a frame was received.
  1089. IpxAddress - The source IPX address of the frame.
  1090. ModifyQueue - TRUE if we should update the queue which this
  1091. cache entry is in, if we reallocate it.
  1092. Return Value:
  1093. The netbios cache entry, either the original or a reallocated one.
  1094. --*/
  1095. {
  1096. PDEVICE Device = NbiDevice;
  1097. USHORT NewNetworks;
  1098. PNETBIOS_CACHE NewNameCache;
  1099. PLIST_ENTRY OldPrevious;
  1100. UINT i;
  1101. //
  1102. // See if we already know about this network.
  1103. //
  1104. for (i = 0; i < NameCache->NetworksUsed; i++) {
  1105. if (NameCache->Networks[i].Network == SourceAddress->NetworkAddress) {
  1106. return NameCache;
  1107. }
  1108. }
  1109. //
  1110. // We need to add information about this network
  1111. // to the name cache entry. If we have to allocate
  1112. // a new one we do that.
  1113. //
  1114. NB_DEBUG2 (CACHE, ("Got new net %lx for <%.16s>\n",
  1115. SourceAddress->NetworkAddress,
  1116. NameCache->NetbiosName));
  1117. if (NameCache->NetworksUsed == NameCache->NetworksAllocated) {
  1118. //
  1119. // We double the number of entries allocated until
  1120. // we hit 16, then add 8 at a time.
  1121. //
  1122. if (NameCache->NetworksAllocated < 16) {
  1123. NewNetworks = NameCache->NetworksAllocated * 2;
  1124. } else {
  1125. NewNetworks = NameCache->NetworksAllocated + 8;
  1126. }
  1127. NewNameCache = NbiAllocateMemory(
  1128. sizeof(NETBIOS_CACHE) + ((NewNetworks-1) * sizeof(NETBIOS_NETWORK)),
  1129. MEMORY_CACHE,
  1130. "Enlarge cache entry");
  1131. if (NewNameCache == NULL) {
  1132. return NameCache;
  1133. }
  1134. NB_DEBUG2 (CACHE, ("Expand cache %lx to %lx for <%.16s>\n",
  1135. NameCache, NewNameCache, NameCache->NetbiosName));
  1136. //
  1137. // Copy the new current data to the new one.
  1138. //
  1139. RtlCopyMemory(
  1140. NewNameCache,
  1141. NameCache,
  1142. sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)));
  1143. NewNameCache->NetworksAllocated = NewNetworks;
  1144. NewNameCache->ReferenceCount = 1;
  1145. if (ModifyQueue) {
  1146. //
  1147. // Insert at the same place as the old one. The time
  1148. // stamp is the same as the old one.
  1149. //
  1150. ReinsertInNetbiosCacheTable( Device->NameCache, NameCache, NewNameCache );
  1151. }
  1152. if (--NameCache->ReferenceCount == 0) {
  1153. NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", NameCache));
  1154. NbiFreeMemory(
  1155. NameCache,
  1156. sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1157. MEMORY_CACHE,
  1158. "Enlarge existing");
  1159. }
  1160. NameCache = NewNameCache;
  1161. }
  1162. NameCache->Networks[NameCache->NetworksUsed].Network =
  1163. SourceAddress->NetworkAddress;
  1164. //
  1165. // If this packet was not routed to us, then store the local
  1166. // target for a correct broadcast.
  1167. //
  1168. if (RtlEqualMemory (RemoteAddress->MacAddress, SourceAddress->NodeAddress, 6)) {
  1169. #if defined(_PNP_POWER)
  1170. NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicHandle = RemoteAddress->NicHandle;
  1171. #else
  1172. NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicId = RemoteAddress->NicId;
  1173. #endif _PNP_POWER
  1174. RtlCopyMemory (NameCache->Networks[NameCache->NetworksUsed].LocalTarget.MacAddress, BroadcastAddress, 6);
  1175. } else {
  1176. NameCache->Networks[NameCache->NetworksUsed].LocalTarget = *RemoteAddress;
  1177. }
  1178. ++NameCache->NetworksUsed;
  1179. return NameCache;
  1180. } /* CacheUpdateNameCache */
  1181. VOID
  1182. CacheUpdateFromAddName(
  1183. IN PIPX_LOCAL_TARGET RemoteAddress,
  1184. IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
  1185. IN BOOLEAN LocalFrame
  1186. )
  1187. /*++
  1188. Routine Description:
  1189. This routine is called when an add name frame is received.
  1190. If it is for a group name it checks if our cache entry for
  1191. that group name needs to be updated to include a new network;
  1192. for all frames it checks if our broadcast cache entry needs
  1193. to be updated to include a new network.
  1194. Arguments:
  1195. RemoteAddress - The address the frame was received from.
  1196. Connectionless - The header of the received add name.
  1197. LocalFrame - TRUE if the frame was sent locally.
  1198. Return Value:
  1199. None.
  1200. --*/
  1201. {
  1202. PUCHAR NetbiosName;
  1203. PNETBIOS_CACHE NameCache;
  1204. PLIST_ENTRY p;
  1205. PDEVICE Device = NbiDevice;
  1206. NB_DEFINE_LOCK_HANDLE (LockHandle)
  1207. NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
  1208. //
  1209. // First look up the broadcast name.
  1210. //
  1211. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  1212. if (!LocalFrame) {
  1213. if ( FindInNetbiosCacheTable( Device->NameCache,
  1214. NetbiosBroadcastName,
  1215. &NameCache ) == STATUS_SUCCESS ) {
  1216. //
  1217. // This will reallocate a cache entry and update the
  1218. // queue if necessary.
  1219. //
  1220. (VOID)CacheUpdateNameCache(
  1221. NameCache,
  1222. RemoteAddress,
  1223. (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
  1224. TRUE);
  1225. }
  1226. }
  1227. //
  1228. // Now see if our database needs to be updated based on this.
  1229. //
  1230. if ( FindInNetbiosCacheTable( Device->NameCache,
  1231. Connectionless->NameFrame.Name,
  1232. &NameCache ) == STATUS_SUCCESS ) {
  1233. if (!NameCache->Unique) {
  1234. if (!LocalFrame) {
  1235. //
  1236. // This will reallocate a cache entry and update the
  1237. // queue if necessary.
  1238. //
  1239. (VOID)CacheUpdateNameCache(
  1240. NameCache,
  1241. RemoteAddress,
  1242. (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
  1243. TRUE);
  1244. }
  1245. } else {
  1246. //
  1247. // To be safe, delete any unique names we get add
  1248. // names for (we will requery next time we need it).
  1249. //
  1250. RemoveFromNetbiosCacheTable ( Device->NameCache, NameCache );
  1251. if (--NameCache->ReferenceCount == 0) {
  1252. NB_DEBUG2 (CACHE, ("Free add named cache entry %lx\n", NameCache));
  1253. NbiFreeMemory(
  1254. NameCache,
  1255. sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1256. MEMORY_CACHE,
  1257. "Enlarge existing");
  1258. }
  1259. }
  1260. }
  1261. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1262. } /* CacheUpdateFromAddName */
  1263. VOID
  1264. NbiProcessDeleteName(
  1265. IN PIPX_LOCAL_TARGET RemoteAddress,
  1266. IN ULONG MacOptions,
  1267. IN PUCHAR PacketBuffer,
  1268. IN UINT PacketSize
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This routine handles NB_CMD_DELETE_NAME frames.
  1273. Arguments:
  1274. RemoteAddress - The local target this packet was received from.
  1275. MacOptions - The MAC options for the underlying NDIS binding.
  1276. LookaheadBuffer - The packet data, starting at the IPX
  1277. header.
  1278. PacketSize - The total length of the packet, starting at the
  1279. IPX header.
  1280. Return Value:
  1281. None.
  1282. --*/
  1283. {
  1284. NB_CONNECTIONLESS UNALIGNED * Connectionless =
  1285. (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
  1286. PUCHAR NetbiosName;
  1287. PNETBIOS_CACHE CacheName;
  1288. PDEVICE Device = NbiDevice;
  1289. NB_DEFINE_LOCK_HANDLE (LockHandle)
  1290. if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
  1291. return;
  1292. }
  1293. //
  1294. // We want to update our netbios cache to reflect the
  1295. // fact that this name is no longer valid.
  1296. //
  1297. NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
  1298. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
  1299. if ( FindInNetbiosCacheTable( Device->NameCache,
  1300. NetbiosName,
  1301. &CacheName ) == STATUS_SUCCESS ) {
  1302. //
  1303. // We don't track group names since we don't know if
  1304. // this is the last person that owns it. We also drop
  1305. // the frame if does not come from the person we think
  1306. // owns this name.
  1307. //
  1308. if ((!CacheName->Unique) ||
  1309. (CacheName->NetworksUsed == 0) ||
  1310. (!RtlEqualMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12))) {
  1311. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1312. return;
  1313. }
  1314. NB_DEBUG2 (CACHE, ("Found cache name to delete <%.16s>\n", NetbiosName));
  1315. }else {
  1316. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1317. return;
  1318. }
  1319. //
  1320. // We have a cache entry, take it out of the list. If no
  1321. // one else is using it, delete it; if not, they will delete
  1322. // it when they are done.
  1323. //
  1324. RemoveFromNetbiosCacheTable ( Device->NameCache, CacheName);
  1325. if (--CacheName->ReferenceCount == 0) {
  1326. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1327. NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
  1328. NbiFreeMemory(
  1329. CacheName,
  1330. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1331. MEMORY_CACHE,
  1332. "Name deleted");
  1333. } else {
  1334. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
  1335. }
  1336. } /* NbiProcessDeleteName */
  1337. VOID
  1338. InsertInNetbiosCacheTable(
  1339. IN PNETBIOS_CACHE_TABLE CacheTable,
  1340. IN PNETBIOS_CACHE CacheEntry
  1341. )
  1342. /*++
  1343. Routine Description:
  1344. This routine inserts a new cache entry in the hash table
  1345. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1346. WITH THE LOCK HELD.
  1347. Arguments:
  1348. CacheTable - The pointer of the Hash Table.
  1349. CacheEntry - Entry to be inserted.
  1350. Return Value:
  1351. None
  1352. --*/
  1353. {
  1354. USHORT HashIndex;
  1355. //
  1356. // Keep a threshold of how many entries do we keep in the table.
  1357. // If it crosses the threshold, just remove the oldest entry
  1358. //
  1359. if ( CacheTable->CurrentEntries >= CacheTable->MaxHashIndex * NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET ) {
  1360. PNETBIOS_CACHE OldestCacheEntry = NULL;
  1361. PNETBIOS_CACHE NextEntry;
  1362. PLIST_ENTRY p;
  1363. for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
  1364. if ( (p = CacheTable->Bucket[ HashIndex ].Blink ) != &CacheTable->Bucket[ HashIndex ] ) {
  1365. NextEntry = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
  1366. if ( OldestCacheEntry ) {
  1367. if ( NextEntry->TimeStamp < OldestCacheEntry->TimeStamp ) {
  1368. OldestCacheEntry = NextEntry;
  1369. }
  1370. } else {
  1371. OldestCacheEntry = NextEntry;
  1372. }
  1373. }
  1374. }
  1375. CTEAssert( OldestCacheEntry );
  1376. NB_DEBUG2 (CACHE, ("Threshold exceeded, removing oldest cache entry %lx\n", OldestCacheEntry));
  1377. RemoveEntryList (&OldestCacheEntry->Linkage);
  1378. CacheTable->CurrentEntries--;
  1379. if (--OldestCacheEntry->ReferenceCount == 0) {
  1380. NB_DEBUG2 (CACHE, ("Freed cache entry %lx\n", OldestCacheEntry));
  1381. NbiFreeMemory(
  1382. OldestCacheEntry,
  1383. sizeof(NETBIOS_CACHE) + ((OldestCacheEntry->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1384. MEMORY_CACHE,
  1385. "Aged out");
  1386. }
  1387. }
  1388. HashIndex = ( ( CacheEntry->NetbiosName[0] & 0x0f ) << 4 ) + ( CacheEntry->NetbiosName[1] & 0x0f );
  1389. HashIndex = HashIndex % CacheTable->MaxHashIndex;
  1390. InsertHeadList( &CacheTable->Bucket[HashIndex], &CacheEntry->Linkage );
  1391. CacheTable->CurrentEntries++;
  1392. } /* InsertInNetbiosCacheTable */
  1393. __inline
  1394. VOID
  1395. ReinsertInNetbiosCacheTable(
  1396. IN PNETBIOS_CACHE_TABLE CacheTable,
  1397. IN PNETBIOS_CACHE OldEntry,
  1398. IN PNETBIOS_CACHE NewEntry
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. This routine inserts a new cache entry at the same place where
  1403. the old entry was.
  1404. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1405. WITH THE LOCK HELD.
  1406. Arguments:
  1407. CacheTable - The pointer of the Hash Table.
  1408. CacheEntry - Entry to be inserted.
  1409. Return Value:
  1410. None
  1411. --*/
  1412. {
  1413. PLIST_ENTRY OldPrevious;
  1414. OldPrevious = OldEntry->Linkage.Blink;
  1415. RemoveEntryList (&OldEntry->Linkage);
  1416. InsertHeadList (OldPrevious, &NewEntry->Linkage);
  1417. } /* ReinsertInNetbiosCacheTable */
  1418. __inline
  1419. VOID
  1420. RemoveFromNetbiosCacheTable(
  1421. IN PNETBIOS_CACHE_TABLE CacheTable,
  1422. IN PNETBIOS_CACHE CacheEntry
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. This routine removes an entry from the cache table.
  1427. Arguments:
  1428. CacheTable - The pointer of the Hash Table.
  1429. CacheEntry - Entry to be removed.
  1430. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1431. WITH THE LOCK HELD.
  1432. Return Value:
  1433. None.
  1434. --*/
  1435. {
  1436. RemoveEntryList( &CacheEntry->Linkage );
  1437. CacheTable->CurrentEntries--;
  1438. } /* RemoveFromNetbiosCacheTable */
  1439. VOID
  1440. FlushOldFromNetbiosCacheTable(
  1441. IN PNETBIOS_CACHE_TABLE CacheTable,
  1442. IN USHORT AgeLimit
  1443. )
  1444. /*++
  1445. Routine Description:
  1446. This routine removes all the old entries from the hash table.
  1447. Arguments:
  1448. CacheTable - The pointer of the Hash Table.
  1449. AgeLimit - All the entries older than AgeLimit will be removed.
  1450. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1451. WITH THE LOCK HELD.
  1452. Return Value:
  1453. None.
  1454. --*/
  1455. {
  1456. USHORT HashIndex;
  1457. PLIST_ENTRY p;
  1458. PNETBIOS_CACHE CacheName;
  1459. //
  1460. // run the hash table looking for old entries. Since new entries
  1461. // are stored at the head and all entries are time stamped when
  1462. // they are inserted, we scan backwards and stop once we find
  1463. // an entry which does not need to be aged.
  1464. // we repeat this for each bucket.
  1465. for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
  1466. for (p = CacheTable->Bucket[ HashIndex ].Blink;
  1467. p != &CacheTable->Bucket[ HashIndex ];
  1468. ) {
  1469. CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
  1470. p = p->Blink;
  1471. //
  1472. // see if any entries have been around for more than agelimit
  1473. //
  1474. if ((USHORT)(NbiDevice->CacheTimeStamp - CacheName->TimeStamp) >= AgeLimit ) {
  1475. RemoveEntryList (&CacheName->Linkage);
  1476. CacheTable->CurrentEntries--;
  1477. if (--CacheName->ReferenceCount == 0) {
  1478. NB_DEBUG2 (CACHE, ("Aging out name cache entry %lx\n", CacheName));
  1479. NbiFreeMemory(
  1480. CacheName,
  1481. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1482. MEMORY_CACHE,
  1483. "Aged out");
  1484. }
  1485. } else {
  1486. break;
  1487. }
  1488. } // for loop
  1489. } // for loop
  1490. } /* FlushOldFromNetbiosCacheTable */
  1491. VOID
  1492. FlushFailedNetbiosCacheEntries(
  1493. IN PNETBIOS_CACHE_TABLE CacheTable
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. This routine removes all the failed entries from the hash table.
  1498. Arguments:
  1499. CacheTable - The pointer of the Hash Table.
  1500. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1501. WITH THE LOCK HELD.
  1502. Return Value:
  1503. None.
  1504. --*/
  1505. {
  1506. USHORT HashIndex;
  1507. PLIST_ENTRY p;
  1508. PNETBIOS_CACHE CacheName;
  1509. if (NULL == CacheTable) {
  1510. return;
  1511. }
  1512. //
  1513. // run the hash table looking for old entries. Since new entries
  1514. // are stored at the head and all entries are time stamped when
  1515. // they are inserted, we scan backwards and stop once we find
  1516. // an entry which does not need to be aged.
  1517. // we repeat this for each bucket.
  1518. for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
  1519. for (p = CacheTable->Bucket[ HashIndex ].Blink;
  1520. p != &CacheTable->Bucket[ HashIndex ];
  1521. ) {
  1522. CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
  1523. p = p->Blink;
  1524. //
  1525. // flush all the failed cache entries.
  1526. // We do this when a new adapter appears, and there's a possiblity that
  1527. // the failed entries might succeed now on the new adapter.
  1528. //
  1529. if (CacheName->NetworksUsed == 0) {
  1530. RemoveEntryList (&CacheName->Linkage);
  1531. CacheTable->CurrentEntries--;
  1532. CTEAssert( CacheName->ReferenceCount == 1 );
  1533. CTEAssert( CacheName->NetworksAllocated == 1 );
  1534. NB_DEBUG2 (CACHE, ("Flushing out failed name cache entry %lx\n", CacheName));
  1535. NbiFreeMemory(
  1536. CacheName,
  1537. sizeof(NETBIOS_CACHE),
  1538. MEMORY_CACHE,
  1539. "Aged out");
  1540. }
  1541. } // for loop
  1542. } // for loop
  1543. } /* FlushFailedNetbiosCacheEntries */
  1544. VOID
  1545. RemoveInvalidRoutesFromNetbiosCacheTable(
  1546. IN PNETBIOS_CACHE_TABLE CacheTable,
  1547. IN NIC_HANDLE UNALIGNED *InvalidNicHandle
  1548. )
  1549. /*++
  1550. Routine Description:
  1551. This routine removes all invalid route entries from the hash table.
  1552. Routes become invalid when the binding is deleted in Ipx due to PnP
  1553. event.
  1554. Arguments:
  1555. CacheTable - The pointer of the Hash Table.
  1556. InvalidRouteNicId - NicId of the invalid routes.
  1557. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1558. WITH THE LOCK HELD.
  1559. Return Value:
  1560. None.
  1561. --*/
  1562. {
  1563. PLIST_ENTRY p;
  1564. PNETBIOS_CACHE CacheName;
  1565. USHORT i,j,NetworksRemoved;
  1566. USHORT HashIndex;
  1567. PDEVICE Device = NbiDevice;
  1568. //
  1569. // Flush all the cache entries that are using this NicId in the local
  1570. // target.
  1571. //
  1572. for ( HashIndex = 0; HashIndex < Device->NameCache->MaxHashIndex; HashIndex++) {
  1573. for (p = Device->NameCache->Bucket[ HashIndex ].Flink;
  1574. p != &Device->NameCache->Bucket[ HashIndex ];
  1575. ) {
  1576. CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
  1577. p = p->Flink;
  1578. //
  1579. // Remove each of those routes which is using this NicId.
  1580. // if no routes left, then flush the cache entry also.
  1581. // ( unique names have only one route anyways )
  1582. //
  1583. for ( i = 0, NetworksRemoved = 0; i < CacheName->NetworksUsed; i++ ) {
  1584. if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId == InvalidNicHandle->NicId ) {
  1585. CTEAssert( RtlEqualMemory( &CacheName->Networks[i].LocalTarget.NicHandle, InvalidNicHandle, sizeof(NIC_HANDLE)));
  1586. for ( j = i+1; j < CacheName->NetworksUsed; j++ ) {
  1587. CacheName->Networks[j-1] = CacheName->Networks[j];
  1588. }
  1589. NetworksRemoved++;
  1590. } else if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId > InvalidNicHandle->NicId ) {
  1591. CacheName->Networks[i].LocalTarget.NicHandle.NicId--;
  1592. }
  1593. }
  1594. CTEAssert( NetworksRemoved <= CacheName->NetworksUsed );
  1595. if ( ! ( CacheName->NetworksUsed -= NetworksRemoved ) ) {
  1596. RemoveEntryList (&CacheName->Linkage);
  1597. CacheTable->CurrentEntries--;
  1598. NB_DEBUG2 (CACHE, ("Removed cache entry %lx bcoz route(NicId %d) deleted\n", CacheName, InvalidNicHandle->NicId ));
  1599. if (--CacheName->ReferenceCount == 0) {
  1600. NB_DEBUG2 (CACHE, ("Freed name cache entry %lx\n", CacheName));
  1601. NbiFreeMemory(
  1602. CacheName,
  1603. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1604. MEMORY_CACHE,
  1605. "Aged out");
  1606. }
  1607. }
  1608. } // for loop
  1609. } // for loop
  1610. } /* RemoveInvalidRoutesFromNetbiosCacheTable */
  1611. NTSTATUS
  1612. FindInNetbiosCacheTable(
  1613. IN PNETBIOS_CACHE_TABLE CacheTable,
  1614. IN PUCHAR NameToBeFound,
  1615. OUT PNETBIOS_CACHE *CacheEntry
  1616. )
  1617. /*++
  1618. Routine Description:
  1619. This routine finds a netbios name in the Hash Table and returns
  1620. the corresponding cache entry.
  1621. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1622. WITH THE LOCK HELD.
  1623. Arguments:
  1624. CacheTable - The pointer of the Hash Table.
  1625. CacheEntry - Pointer to the netbios cache entry if found.
  1626. Return Value:
  1627. STATUS_SUCCESS - if successful.
  1628. STATUS_UNSUCCESSFUL - otherwise.
  1629. --*/
  1630. {
  1631. USHORT HashIndex;
  1632. PLIST_ENTRY p;
  1633. PNETBIOS_CACHE FoundCacheName;
  1634. HashIndex = ( ( NameToBeFound[0] & 0x0f ) << 4 ) + ( NameToBeFound[1] & 0x0f );
  1635. HashIndex = HashIndex % CacheTable->MaxHashIndex;
  1636. for (p = ( CacheTable->Bucket[ HashIndex ] ).Flink;
  1637. p != &CacheTable->Bucket[ HashIndex ];
  1638. p = p->Flink) {
  1639. FoundCacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
  1640. //
  1641. // See if this entry is for the same name we are looking for.
  1642. if ( RtlEqualMemory (FoundCacheName->NetbiosName, NameToBeFound, 16) ) {
  1643. *CacheEntry = FoundCacheName;
  1644. return STATUS_SUCCESS;
  1645. }
  1646. }
  1647. return STATUS_UNSUCCESSFUL;
  1648. } /* FindInNetbiosCacheTable */
  1649. NTSTATUS
  1650. CreateNetbiosCacheTable(
  1651. IN OUT PNETBIOS_CACHE_TABLE *NewTable,
  1652. IN USHORT MaxHashIndex
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. This routine creates a new hash table for netbios cache
  1657. and initializes it.
  1658. THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
  1659. WITH THE LOCK HELD.
  1660. Arguments:
  1661. NewTable - The pointer of the table to be created.
  1662. MaxHashIndex - Number of buckets in the hash table.
  1663. Return Value:
  1664. STATUS_SUCCESS - if successful.
  1665. STATUS_INSUFFICIENT_RESOURCES - If cannot allocate memory.
  1666. --*/
  1667. {
  1668. USHORT i;
  1669. *NewTable = NbiAllocateMemory (sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( MaxHashIndex - 1) ,
  1670. MEMORY_CACHE, "Cache Table");
  1671. if ( *NewTable ) {
  1672. for ( i = 0; i < MaxHashIndex; i++ ) {
  1673. InitializeListHead(& (*NewTable)->Bucket[i] );
  1674. }
  1675. (*NewTable)->MaxHashIndex = MaxHashIndex;
  1676. (*NewTable)->CurrentEntries = 0;
  1677. return STATUS_SUCCESS;
  1678. }
  1679. else {
  1680. NB_DEBUG( CACHE, ("Cannot create Netbios Cache Table\n") );
  1681. return STATUS_INSUFFICIENT_RESOURCES;
  1682. }
  1683. } /* CreateNetbiosCacheTable */
  1684. VOID
  1685. DestroyNetbiosCacheTable(
  1686. IN PNETBIOS_CACHE_TABLE CacheTable
  1687. )
  1688. /*++
  1689. Routine Description:
  1690. This routine removes all entries from the hash table.
  1691. and free up the hash table.
  1692. Arguments:
  1693. CacheTable - The pointer of the Hash Table.
  1694. Return Value:
  1695. None.
  1696. --*/
  1697. {
  1698. USHORT HashIndex;
  1699. PLIST_ENTRY p;
  1700. PNETBIOS_CACHE CacheName;
  1701. for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
  1702. while (!IsListEmpty ( &( CacheTable->Bucket[ HashIndex ] ) ) ) {
  1703. p = RemoveHeadList ( &( CacheTable->Bucket[ HashIndex ] ));
  1704. CacheTable->CurrentEntries--;
  1705. CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
  1706. NB_DEBUG2 (CACHE, ("Free cache entry %lx\n", CacheName));
  1707. NbiFreeMemory(
  1708. CacheName,
  1709. sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
  1710. MEMORY_CACHE,
  1711. "Free entries");
  1712. }
  1713. } // for loop
  1714. CTEAssert( CacheTable->CurrentEntries == 0 );
  1715. NbiFreeMemory (CacheTable, sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( CacheTable->MaxHashIndex - 1) ,
  1716. MEMORY_CACHE, "Free Cache Table");
  1717. } /* DestroyNetbiosCacheTable */