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.

3914 lines
120 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Namesrv.c
  5. Abstract:
  6. This file contains the name service functions called by other parts of
  7. the NBT code. (QueryNameOnNet, FindName, RegisterName). It also contains
  8. the completion routines for the timeouts associated with these functions.
  9. The pScope values that are passed around from one routine to the next
  10. point to the scope string for the name. If there is no scope then the
  11. pScope ptr points at a single character '\0' - signifying a string of
  12. zero length. Therefore the check for scope is "if (*pScope != 0)"
  13. Author:
  14. Jim Stewart (Jimst) 10-2-92
  15. Revision History:
  16. --*/
  17. #include "precomp.h"
  18. #include "namesrv.tmh"
  19. //
  20. // function prototypes for completion routines that are local to this file
  21. //
  22. NTSTATUS
  23. AddToPendingList(
  24. IN PCHAR pName,
  25. OUT tNAMEADDR **ppNameAddr
  26. );
  27. VOID
  28. MSnodeCompletion(
  29. PVOID pContext,
  30. PVOID pContext2,
  31. tTIMERQENTRY *pTimerQEntry
  32. );
  33. VOID
  34. MSnodeRegCompletion(
  35. PVOID pContext,
  36. PVOID pContext2,
  37. tTIMERQENTRY *pTimerQEntry
  38. );
  39. VOID
  40. SetWinsDownFlag(
  41. tDEVICECONTEXT *pDeviceContext
  42. );
  43. VOID
  44. ReleaseCompletion(
  45. PVOID pContext,
  46. PVOID pContext2,
  47. tTIMERQENTRY *pTimerQEntry
  48. );
  49. VOID
  50. NextRefresh(
  51. IN PVOID pNameAdd,
  52. IN NTSTATUS status
  53. );
  54. VOID
  55. GetNextName(
  56. IN tNAMEADDR *pNameAddrIn,
  57. OUT tNAMEADDR **ppNameAddr
  58. );
  59. NTSTATUS
  60. StartRefresh(
  61. IN tNAMEADDR *pNameAddr,
  62. IN tDGRAM_SEND_TRACKING *pTracker,
  63. IN CTELockHandle *pJointLockOldIrq,
  64. IN BOOLEAN ResetDevice
  65. );
  66. VOID
  67. NextKeepAlive(
  68. IN tDGRAM_SEND_TRACKING *pTracker,
  69. IN NTSTATUS statuss,
  70. IN ULONG Info
  71. );
  72. VOID
  73. GetNextKeepAlive(
  74. tDEVICECONTEXT *pDeviceContext,
  75. tDEVICECONTEXT **ppDeviceContextOut,
  76. tLOWERCONNECTION *pLowerConnIn,
  77. tLOWERCONNECTION **ppLowerConnOut,
  78. tDGRAM_SEND_TRACKING *pTracker
  79. );
  80. VOID
  81. WinsDownTimeout(
  82. PVOID pContext,
  83. PVOID pContext2,
  84. tTIMERQENTRY *pTimerQEntry
  85. );
  86. BOOL
  87. AppropriateNodeType(
  88. IN PCHAR pName,
  89. IN ULONG NodeType
  90. );
  91. BOOL
  92. IsBrowserName(
  93. IN PCHAR pName
  94. );
  95. #if DBG
  96. unsigned char Buff[256];
  97. unsigned char Loc;
  98. #endif
  99. //******************* Pageable Routine Declarations ****************
  100. #ifdef ALLOC_PRAGMA
  101. #pragma CTEMakePageable(PAGE, DelayedSessionKeepAlive)
  102. #endif
  103. //******************* Pageable Routine Declarations ****************
  104. //----------------------------------------------------------------------------
  105. NTSTATUS
  106. AddToPendingList(
  107. IN PCHAR pName,
  108. OUT tNAMEADDR **ppNameAddr
  109. )
  110. /*++
  111. Routine Description:
  112. This routine Adds a name query request to the PendingNameQuery list.
  113. Arguments:
  114. Return Value:
  115. The function value is the status of the operation.
  116. --*/
  117. {
  118. tNAMEADDR *pNameAddr;
  119. pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('R'));
  120. if (pNameAddr)
  121. {
  122. CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
  123. CTEMemCopy(pNameAddr->Name,pName,NETBIOS_NAME_SIZE);
  124. pNameAddr->NameTypeState = STATE_RESOLVING | NBT_UNIQUE;
  125. pNameAddr->Verify = REMOTE_NAME;
  126. pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
  127. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_QUERY_ON_NET);
  128. InsertTailList(&NbtConfig.PendingNameQueries, &pNameAddr->Linkage);
  129. *ppNameAddr = pNameAddr;
  130. return(STATUS_SUCCESS);
  131. }
  132. else
  133. {
  134. return(STATUS_INSUFFICIENT_RESOURCES);
  135. }
  136. }
  137. //----------------------------------------------------------------------------
  138. NTSTATUS
  139. QueryNameOnNet(
  140. IN PCHAR pName,
  141. IN PCHAR pScope,
  142. IN USHORT uType,
  143. IN tDGRAM_SEND_TRACKING *pTrackerClientContext,
  144. IN PVOID pClientCompletion,
  145. IN ULONG LocalNodeType,
  146. IN tNAMEADDR *pNameAddrIn,
  147. IN tDEVICECONTEXT *pDeviceContext,
  148. IN CTELockHandle *pJointLockOldIrq
  149. )
  150. /*++
  151. Routine Description:
  152. This routine attempts to resolve a name on the network either by a
  153. broadcast or by talking to the NS depending on the type of node. (M,P or B)
  154. Arguments:
  155. Return Value:
  156. The function value is the status of the operation.
  157. Called By: ProxyQueryFromNet() in proxy.c, NbtConnect() in name.c
  158. --*/
  159. {
  160. ULONG Timeout;
  161. USHORT Retries;
  162. NTSTATUS status;
  163. PVOID pCompletionRoutine;
  164. tDGRAM_SEND_TRACKING *pTrackerQueryNet;
  165. tNAMEADDR *pNameAddr;
  166. LPVOID pContext2 = NULL;
  167. CHAR cNameType = pName[NETBIOS_NAME_SIZE-1];
  168. BOOL SendFlag = TRUE;
  169. LONG IpAddr = 0;
  170. ULONG Flags;
  171. status = GetTracker(&pTrackerQueryNet, NBT_TRACKER_QUERY_NET);
  172. if (!NT_SUCCESS(status))
  173. {
  174. return(status);
  175. }
  176. if (pTrackerClientContext) // This will be NULL for Proxy requests
  177. {
  178. pTrackerClientContext->pTrackerWorker = pTrackerQueryNet;
  179. }
  180. //
  181. // put the name in the remote cache to keep track of it while it resolves...
  182. //
  183. pNameAddr = NULL;
  184. if (!pNameAddrIn)
  185. {
  186. status = AddToPendingList(pName,&pNameAddr);
  187. if (!NT_SUCCESS(status))
  188. {
  189. FreeTracker(pTrackerQueryNet,RELINK_TRACKER);
  190. return(status);
  191. }
  192. // fill in the record with the name and IpAddress
  193. pNameAddr->NameTypeState = (uType == NBT_UNIQUE) ? NAMETYPE_UNIQUE : NAMETYPE_GROUP;
  194. }
  195. else
  196. {
  197. status = STATUS_SUCCESS;
  198. pNameAddr = pNameAddrIn;
  199. pNameAddr->RefCount = 1;
  200. }
  201. CHECK_PTR(pNameAddr);
  202. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  203. pNameAddr->NameTypeState |= STATE_RESOLVING;
  204. pNameAddr->Ttl = NbtConfig.RemoteHashTtl;
  205. //
  206. // put a pointer to the tracker here so that other clients attempting to
  207. // query the same name at the same time can tack their trackers onto
  208. // the end of this one. - i.e. This is the tracker for the
  209. // datagram send, or connect, not the name query.
  210. //
  211. pNameAddr->pTracker = pTrackerClientContext;
  212. pNameAddr->pTimer = NULL;
  213. #ifdef PROXY_NODE
  214. //
  215. // If the node type is PROXY, it means that the request is being sent
  216. // as a result of hearing a name registration or a name query on the net.
  217. //
  218. // If the node type is not == PROXY (i.e. it is MSNODE | PROXY,
  219. // PNODE | PROXY, MSNODE, PNODE, etc, then the request is being sent as
  220. // a result of a client request
  221. //
  222. // Refer: RegOrQueryFromNet in Proxy.c
  223. //
  224. // This field is used in QueryFromNet() to determine whether or not
  225. // to revert to Broadcast
  226. //
  227. #endif
  228. if(LocalNodeType & PROXY)
  229. {
  230. pNameAddr->ProxyReqType = (LocalNodeType & PROXY_REG)? NAMEREQ_PROXY_REGISTRATION: NAMEREQ_PROXY_QUERY;
  231. LocalNodeType &= (~PROXY_REG); // Turn it off for safe
  232. }
  233. else
  234. {
  235. pNameAddr->ProxyReqType = NAMEREQ_REGULAR;
  236. LocalNodeType = AppropriateNodeType( pName, LocalNodeType );
  237. }
  238. // keep a ptr to the Ascii name so that we can remove the name from the
  239. // hash table later if the query fails.
  240. CHECK_PTR(pTrackerQueryNet);
  241. pTrackerQueryNet->pNameAddr = pNameAddr;
  242. pTrackerQueryNet->SendBuffer.pDgramHdr = NULL; // set to NULL to catch any erroneous frees.
  243. pTrackerQueryNet->pDeviceContext = pDeviceContext;
  244. //
  245. // set the ref count high enough so that a pdu from the wire cannot
  246. // free the tracker while UdpSendNsBcast is running - i.e. between starting
  247. // the timer and actually sending the datagram.
  248. //
  249. pTrackerQueryNet->RefCount = 2;
  250. #ifdef MULTIPLE_WINS
  251. // Set the info for the Extra Name Servers (in addition to Pri & Sec WINs)
  252. pTrackerQueryNet->NSOthersLeft = pDeviceContext->lNumOtherServers;
  253. pTrackerQueryNet->NSOthersIndex = pDeviceContext->lLastResponsive;
  254. #endif
  255. //
  256. // Set a few values as a precursor to registering the name either by
  257. // broadcast or with the name server
  258. //
  259. #ifdef PROXY_NODE
  260. IF_PROXY(LocalNodeType)
  261. {
  262. pCompletionRoutine = ProxyTimerComplFn;
  263. pContext2 = pTrackerClientContext;
  264. pTrackerClientContext = NULL;
  265. if ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
  266. pDeviceContext->WinsIsDown) {
  267. Retries = pNbtGlobConfig->uNumBcasts;
  268. Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
  269. pTrackerQueryNet->Flags = NBT_BROADCAST;
  270. } else {
  271. Retries = (USHORT)pNbtGlobConfig->uNumRetries;
  272. Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
  273. pTrackerQueryNet->Flags = NBT_NAME_SERVER;
  274. }
  275. }
  276. else
  277. #endif
  278. if (NbtConfig.UseDnsOnly)
  279. {
  280. IF_DBG(NBT_DEBUG_NAMESRV)
  281. KdPrint (("Nbt.QueryNameOnNet: Shorting out Query path to do DNS only for %16.16s<%X>\n",
  282. pName,pName[15]));
  283. //
  284. // Short out query over wire
  285. //
  286. Retries = 1;
  287. Timeout = 10;
  288. SendFlag = FALSE;
  289. pCompletionRoutine = MSnodeCompletion;
  290. //
  291. // For BNODE or MSNODE, the last stage is Broadcast
  292. //
  293. if (LocalNodeType & (BNODE | MSNODE))
  294. {
  295. pTrackerQueryNet->Flags = NBT_BROADCAST;
  296. }
  297. //
  298. // For PNODE or MNODE, the last stage is Secondary Wins server
  299. //
  300. else
  301. {
  302. pTrackerQueryNet->Flags = NBT_NAME_SERVER_BACKUP;
  303. }
  304. pTrackerClientContext->ResolutionContextFlags = 0xff;
  305. }
  306. else if ((pTrackerClientContext->pFailedIpAddresses) &&
  307. (pTrackerClientContext->ResolutionContextFlags))
  308. {
  309. //
  310. // We are reattempting the query after the previous attempt failed!
  311. //
  312. pTrackerQueryNet->Flags = pTrackerClientContext->ResolutionContextFlags;
  313. pTrackerQueryNet->NSOthersIndex = pTrackerClientContext->NSOthersIndex;
  314. pTrackerQueryNet->NSOthersLeft = pTrackerClientContext->NSOthersLeft;
  315. //
  316. // Set the Retries to 1 by default so that we can immediately proceed
  317. // to the next stage in the querying process
  318. //
  319. Retries = 1;
  320. Timeout = 10;
  321. SendFlag = FALSE;
  322. pCompletionRoutine = MSnodeCompletion;
  323. }
  324. else
  325. {
  326. Retries = pNbtGlobConfig->uNumRetries;
  327. Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
  328. pCompletionRoutine = MSnodeCompletion;
  329. pTrackerQueryNet->Flags = NBT_NAME_SERVER;
  330. // use broadcast if no name server address for MSNODE or Wins down,
  331. // or it is Bnode,Mnode.
  332. // for Pnode, just allow it to do the name query on the loop back
  333. // address
  334. //
  335. if ((LocalNodeType & (MNODE | BNODE)) ||
  336. ((LocalNodeType & MSNODE) &&
  337. ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
  338. pDeviceContext->WinsIsDown)))
  339. {
  340. Retries = pNbtGlobConfig->uNumBcasts;
  341. Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
  342. pTrackerQueryNet->Flags = NBT_BROADCAST;
  343. }
  344. else if ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
  345. (pDeviceContext->WinsIsDown))
  346. {
  347. //
  348. // short out timeout when no wins server configured -for PNODE
  349. //
  350. Retries = 1;
  351. Timeout = 10;
  352. pTrackerQueryNet->Flags = NBT_NAME_SERVER_BACKUP;
  353. }
  354. //
  355. // no sense doing a name query out an adapter with no Ip address
  356. //
  357. if (pTrackerClientContext)
  358. {
  359. Flags = pTrackerClientContext->Flags;
  360. }
  361. else
  362. {
  363. Flags = 0;
  364. }
  365. if ((pDeviceContext->IpAddress == 0) || (IpAddr = Nbt_inet_addr(pName, Flags)))
  366. {
  367. Retries = 1;
  368. Timeout = 10;
  369. pTrackerQueryNet->Flags = NBT_BROADCAST;
  370. SendFlag = FALSE;
  371. if (LocalNodeType & (PNODE | MNODE))
  372. {
  373. pTrackerQueryNet->Flags = NBT_NAME_SERVER_BACKUP;
  374. }
  375. }
  376. }
  377. CTESpinFree(&NbtConfig.JointLock,*pJointLockOldIrq);
  378. // do a name query... will always return status pending...
  379. // the pNameAddr structure cannot get deleted out from under us since
  380. // only a timeout on the send (3 retries) will remove the name. Any
  381. // response from the net will tend to keep the name (change state to Resolved)
  382. //
  383. //
  384. // Bug: 22542 - prevent broadcast of remote adapter status on net view of limited subnet b'cast address.
  385. // In order to test for subnet broadcasts, we need to match against the subnet masks of all adapters. This
  386. // is expensive and not done.
  387. // Just check for the limited bcast.
  388. //
  389. if (IpAddr == 0xffffffff)
  390. {
  391. KdPrint(("Nbt.QueryNameOnNet: Query on Limited broadcast - failed\n"));
  392. status = STATUS_BAD_NETWORK_PATH;
  393. }
  394. else
  395. {
  396. status = UdpSendNSBcast(pNameAddr,
  397. pScope,
  398. pTrackerQueryNet,
  399. pCompletionRoutine,
  400. pTrackerClientContext,
  401. pClientCompletion,
  402. Retries,
  403. Timeout,
  404. eNAME_QUERY,
  405. SendFlag);
  406. if (!NT_SUCCESS(status)) {
  407. NbtTrace(NBT_TRACE_NAMESRV, ("UdpSendNSBcast return %!status! for %!NBTNAME!<%02x>",
  408. status, pNameAddr->Name, (unsigned)pNameAddr->Name[15]));
  409. }
  410. }
  411. // a successful send means, Don't complete the Irp. Status Pending is
  412. // returned to ntisol.c to tell that code not to complete the irp. The
  413. // irp will be completed when this send either times out or a response
  414. // is heard. In the event of an error in the send, allow that return
  415. // code to propagate back and result in completing the irp - i.e. if
  416. // there isn't enough memory to allocate a buffer or some such thing
  417. //
  418. CTESpinLock(&NbtConfig.JointLock,*pJointLockOldIrq);
  419. NBT_DEREFERENCE_TRACKER (pTrackerQueryNet, TRUE);
  420. if (NT_SUCCESS(status))
  421. {
  422. LOCATION(0x49);
  423. // this return must be here to avoid freeing the tracker below.
  424. status = STATUS_PENDING;
  425. }
  426. else
  427. {
  428. LOCATION(0x50);
  429. IF_DBG(NBT_DEBUG_NAMESRV)
  430. KdPrint(("Nbt.QueryNameOnNet: Query failed - bad retcode from UdpSendNsBcast = %X\n", status));
  431. //
  432. // UdpSendNsBcast should not fail AND start the timer, therefore there
  433. // is no need to worry about stopping the timer here.
  434. //
  435. CHECK_PTR(pNameAddr);
  436. pNameAddr->pTimer = NULL;
  437. if (pTrackerClientContext)
  438. {
  439. pTrackerClientContext->pTrackerWorker = NULL;
  440. }
  441. //
  442. // This will free the tracker
  443. //
  444. NBT_DEREFERENCE_TRACKER (pTrackerQueryNet, TRUE);
  445. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  446. }
  447. return(status);
  448. }
  449. #ifdef MULTIPLE_WINS
  450. //----------------------------------------------------------------------------
  451. NTSTATUS
  452. ContinueQueryNameOnNet(
  453. IN tDGRAM_SEND_TRACKING *pTracker,
  454. IN PUCHAR pName,
  455. IN tDEVICECONTEXT *pDeviceContext,
  456. IN PVOID QueryCompletion,
  457. IN OUT BOOLEAN *pfNameReferenced
  458. )
  459. /*++
  460. Routine Description
  461. This routine handles re-querying a name on the network.
  462. Arguments:
  463. Return Values:
  464. NTSTATUS - status of the request
  465. --*/
  466. {
  467. CTELockHandle OldIrq2;
  468. ULONG lNameType;
  469. NTSTATUS status;
  470. tNAMEADDR *pNameAddr;
  471. tIPADDRESS IpAddress;
  472. ASSERT (!IsDeviceNetbiosless(pDeviceContext));
  473. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  474. //
  475. // Name and Tracker should be currently Referenced!
  476. //
  477. ASSERT (NBT_VERIFY_HANDLE (pTracker, NBT_VERIFY_TRACKER));
  478. ASSERT (NBT_VERIFY_HANDLE2(pTracker->pNameAddr, LOCAL_NAME, REMOTE_NAME));
  479. //
  480. // If no one else is referencing the name, then delete it from
  481. // the hash table.
  482. //
  483. pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  484. pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
  485. if ((pTracker->pNameAddr->Verify == REMOTE_NAME) &&
  486. (pTracker->pNameAddr->NameTypeState & STATE_RESOLVED) &&
  487. (pTracker->pNameAddr->RefCount == 2))
  488. {
  489. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_REMOTE, TRUE);
  490. }
  491. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  492. pTracker->pNameAddr = NULL;
  493. *pfNameReferenced = FALSE;
  494. //
  495. // no sense re-doing a name query if:
  496. // the request has been cancelled, or
  497. // adapter has no Ip address, or
  498. // the name given is itself an IP address!
  499. // the previous query had finished querying all the WINS servers
  500. //
  501. if ((pTracker->Flags & TRACKER_CANCELLED) ||
  502. (!pDeviceContext->IpAddress) ||
  503. (Nbt_inet_addr(pName, SESSION_SETUP_FLAG)) ||
  504. (pTracker->ResolutionContextFlags == 0xff))
  505. {
  506. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  507. return (STATUS_BAD_NETWORK_PATH);
  508. }
  509. //
  510. // Save the last Ip address we tried as bad!
  511. //
  512. if (!pTracker->pFailedIpAddresses)
  513. {
  514. if (!(pTracker->pFailedIpAddresses =
  515. NbtAllocMem ((MAX_FAILED_IP_ADDRESSES) * sizeof(tIPADDRESS), NBT_TAG2('04'))))
  516. {
  517. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  518. return (STATUS_INSUFFICIENT_RESOURCES);
  519. }
  520. CTEZeroMemory(pTracker->pFailedIpAddresses,(MAX_FAILED_IP_ADDRESSES) * sizeof(tIPADDRESS));
  521. }
  522. pTracker->pFailedIpAddresses[pTracker->LastFailedIpIndex] = pTracker->RemoteIpAddress;
  523. pTracker->LastFailedIpIndex = (pTracker->LastFailedIpIndex+1) % MAX_FAILED_IP_ADDRESSES;
  524. // check the Remote table to see if the name has been resolved
  525. // by someone else
  526. //
  527. if ((pNameAddr = FindNameRemoteThenLocal(pTracker, &IpAddress, &lNameType)) &&
  528. (IpAddress) &&
  529. (pNameAddr->NameTypeState & STATE_RESOLVED) &&
  530. (IpAddress != pTracker->RemoteIpAddress))
  531. {
  532. //
  533. // We have another address to try!
  534. //
  535. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_CONNECT);
  536. *pfNameReferenced = TRUE;
  537. pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
  538. pTracker->pNameAddr = pNameAddr;
  539. // set the session state to NBT_CONNECTING
  540. CHECK_PTR(pTracker->pConnEle);
  541. SET_STATE_UPPER (pTracker->pConnEle, NBT_CONNECTING);
  542. pTracker->pConnEle->BytesRcvd = 0;;
  543. pTracker->pConnEle->ReceiveIndicated = 0;
  544. // keep track of the other end's ip address
  545. pTracker->pConnEle->pLowerConnId->SrcIpAddr = htonl(IpAddress);
  546. SET_STATE_LOWER (pTracker->pConnEle->pLowerConnId, NBT_CONNECTING);
  547. pTracker->pTrackerWorker = NULL;
  548. IF_DBG(NBT_DEBUG_NAMESRV)
  549. KdPrint(("Nbt.NbtConnectCommon: Setting Up Session(cached entry!!) to %16.16s <%X>\n",
  550. pNameAddr->Name,pNameAddr->Name[15]));
  551. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  552. //
  553. // Now, setup the Tcp connection
  554. //
  555. status = TcpSessionStart (pTracker,
  556. IpAddress,
  557. (tDEVICECONTEXT *)pTracker->pDeviceContext,
  558. SessionStartupContinue,
  559. pTracker->DestPort);
  560. }
  561. else
  562. {
  563. status = QueryNameOnNet (pName,
  564. NbtConfig.pScope,
  565. NBT_UNIQUE,
  566. pTracker,
  567. QueryCompletion,
  568. NodeType & NODE_MASK,
  569. NULL,
  570. pDeviceContext,
  571. &OldIrq2);
  572. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  573. }
  574. return (status);
  575. }
  576. #endif
  577. //----------------------------------------------------------------------------
  578. VOID
  579. MSnodeCompletion(
  580. PVOID pContext,
  581. PVOID pContext2,
  582. tTIMERQENTRY *pTimerQEntry
  583. )
  584. /*++
  585. Routine Description:
  586. This routine is called by the timer code when the timer expires. It must
  587. decide if another name query should be done, and if not, then it calls the
  588. client's completion routine (in completion2).
  589. This routine handles the broadcast portion of the name queries (i.e.
  590. those name queries that go out as broadcasts).
  591. Arguments:
  592. Return Value:
  593. The function value is the status of the operation.
  594. --*/
  595. {
  596. NTSTATUS status;
  597. tDGRAM_SEND_TRACKING *pTracker;
  598. CTELockHandle OldIrq;
  599. COMPLETIONCLIENT pClientCompletion;
  600. ULONG Flags;
  601. tDGRAM_SEND_TRACKING *pClientTracker;
  602. ULONG LocalNodeType;
  603. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  604. LocalNodeType = AppropriateNodeType( pTracker->pNameAddr->Name, NodeType );
  605. //
  606. // check if the client completion routine is still set. If not then the
  607. // timer has been cancelled and this routine should just clean up its
  608. // buffers associated with the tracker.
  609. //
  610. if (!pTimerQEntry)
  611. {
  612. // return the tracker block to its queue
  613. pTracker->pNameAddr->pTimer = NULL;
  614. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  615. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  616. return;
  617. }
  618. //
  619. // to prevent a client from stopping the timer and deleting the
  620. // pNameAddr, grab the lock and check if the timer has been stopped
  621. //
  622. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  623. ASSERT (NBT_VERIFY_HANDLE (pTracker->pNameAddr, REMOTE_NAME));
  624. //
  625. // StopTimer could have been called before we acquired the lock, so
  626. // check for this
  627. // Bug#: 229616
  628. //
  629. if (!pTimerQEntry->ClientCompletion)
  630. {
  631. pTracker->pNameAddr->pTimer = NULL;
  632. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  633. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  634. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  635. return;
  636. }
  637. if (pTimerQEntry->Flags & TIMER_RETIMED)
  638. {
  639. pTimerQEntry->Flags &= ~TIMER_RETIMED;
  640. pTimerQEntry->Flags |= TIMER_RESTART;
  641. //
  642. // if we are not bound to this card than use a very short timeout
  643. //
  644. if (!pTracker->pDeviceContext->IpAddress)
  645. {
  646. pTimerQEntry->DeltaTime = 10;
  647. }
  648. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  649. return;
  650. }
  651. pClientTracker = (tDGRAM_SEND_TRACKING *)pTimerQEntry->ClientContext;
  652. //
  653. // if the tracker has been cancelled, don't do any more queries
  654. //
  655. if (pClientTracker->Flags & TRACKER_CANCELLED)
  656. {
  657. IF_DBG(NBT_DEBUG_NAMESRV)
  658. KdPrint(("Nbt.MSnodeCompletion: tracker flag cancelled\n"));
  659. //
  660. // In case the timer has been stopped, we coordinate
  661. // through the pClientCompletionRoutine Value with StopTimer.
  662. //
  663. pClientCompletion = pTimerQEntry->ClientCompletion;
  664. //
  665. // remove from the PendingNameQueries list
  666. //
  667. RemoveEntryList(&pTracker->pNameAddr->Linkage);
  668. InitializeListHead(&pTracker->pNameAddr->Linkage);
  669. // remove the link from the name table to this timer block
  670. CHECK_PTR(((tNAMEADDR *)pTimerQEntry->pCacheEntry));
  671. ((tNAMEADDR *)pTimerQEntry->pCacheEntry)->pTimer = NULL;
  672. //
  673. // to synch. with the StopTimer routine, Null the client completion
  674. // routine so it gets called just once.
  675. //
  676. CHECK_PTR(pTimerQEntry);
  677. pTimerQEntry->ClientCompletion = NULL;
  678. //
  679. // remove the name from the hash table, since it did not
  680. // resolve
  681. //
  682. CHECK_PTR(pTracker->pNameAddr);
  683. pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  684. pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
  685. pTracker->pNameAddr->pTimer = NULL;
  686. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  687. pTracker->pNameAddr = NULL;
  688. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  689. // there can be a list of trackers Q'd up on this name
  690. // query, so we must complete all of them!
  691. //
  692. CompleteClientReq(pClientCompletion, pClientTracker, STATUS_CANCELLED);
  693. // return the tracker block to its queue
  694. LOCATION(0x51);
  695. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  696. return;
  697. }
  698. // if number of retries is not zero then continue trying to contact the
  699. // Name Server.
  700. //
  701. if (!(--pTimerQEntry->Retries))
  702. {
  703. // set the retry count again
  704. //
  705. pTimerQEntry->Retries = NbtConfig.uNumRetries;
  706. Flags = pTracker->Flags;
  707. pTracker->Flags &= ~(NBT_NAME_SERVER_BACKUP
  708. #ifdef MULTIPLE_WINS
  709. | NBT_NAME_SERVER_OTHERS
  710. #endif
  711. | NBT_NAME_SERVER
  712. | NBT_BROADCAST);
  713. if ((Flags & NBT_BROADCAST) && (LocalNodeType & MNODE) &&
  714. (pTracker->pDeviceContext->lNameServerAddress != LOOP_BACK) &&
  715. !pTracker->pDeviceContext->WinsIsDown)
  716. {
  717. LOCATION(0x44);
  718. // *** MNODE ONLY ***
  719. //
  720. // Can't Resolve through broadcast, so try the name server
  721. //
  722. pTracker->Flags |= NBT_NAME_SERVER;
  723. // set a different timeout for name resolution through WINS
  724. //
  725. pTimerQEntry->DeltaTime = NbtConfig.uRetryTimeout;
  726. }
  727. else if ((Flags & NBT_NAME_SERVER) && !(LocalNodeType & BNODE))
  728. {
  729. LOCATION(0x47);
  730. // *** NOT BNODE ***
  731. //
  732. // Can't reach the name server, so try the backup
  733. //
  734. pTracker->Flags |= NBT_NAME_SERVER_BACKUP;
  735. //
  736. // short out the timeout if no backup name server
  737. //
  738. if ((pTracker->pDeviceContext->lBackupServer == LOOP_BACK) ||
  739. pTracker->pDeviceContext->WinsIsDown)
  740. {
  741. pTimerQEntry->Retries = 1;
  742. pTimerQEntry->DeltaTime = 10;
  743. }
  744. }
  745. #ifdef MULTIPLE_WINS
  746. else if ((Flags & NBT_NAME_SERVER_BACKUP) && !(LocalNodeType & BNODE))
  747. {
  748. //
  749. // Main backup and possibly some of the "others" have
  750. // failed, see if there are any (more) "others" left
  751. //
  752. USHORT Index = pTracker->NSOthersIndex;
  753. USHORT NumBackups = pTracker->pDeviceContext->lNumOtherServers;
  754. pTracker->Flags |= NBT_NAME_SERVER_OTHERS;
  755. if (Flags & NBT_NAME_SERVER_OTHERS) // not 1st time here
  756. { // so, move to next server
  757. pTracker->NSOthersLeft--;
  758. if (Index >= NumBackups-1)
  759. {
  760. Index = 0;
  761. }
  762. else
  763. {
  764. Index++;
  765. }
  766. }
  767. while ((pTracker->NSOthersLeft > 0) &&
  768. (LOOP_BACK == pTracker->pDeviceContext->lOtherServers[Index]))
  769. {
  770. pTracker->NSOthersLeft--;
  771. if (Index >= NumBackups-1)
  772. {
  773. Index = 0;
  774. }
  775. else
  776. {
  777. Index++;
  778. }
  779. }
  780. pTracker->NSOthersIndex = Index;
  781. //
  782. // short out the timeout if we did not find any "other" name servers
  783. //
  784. if (0 == pTracker->NSOthersLeft) // UdpSendNSBcast will do LOOP_BACK
  785. {
  786. pTimerQEntry->Retries = 1;
  787. pTimerQEntry->DeltaTime = 10;
  788. }
  789. else
  790. {
  791. pTracker->Flags |= NBT_NAME_SERVER_BACKUP; // Try next "other" server on timeout
  792. }
  793. }
  794. else if ((Flags & NBT_NAME_SERVER_OTHERS)
  795. #else
  796. else if ((Flags & NBT_NAME_SERVER_BACKUP)
  797. #endif
  798. && (LocalNodeType & MSNODE))
  799. {
  800. LOCATION(0x46);
  801. // *** MSNODE ONLY ***
  802. //
  803. // Can't reach the name server(s), so try broadcast name queries
  804. //
  805. pTracker->Flags |= NBT_BROADCAST;
  806. // set a different timeout for broadcast name resolution
  807. //
  808. pTimerQEntry->DeltaTime = NbtConfig.uBcastTimeout;
  809. pTimerQEntry->Retries = NbtConfig.uNumBcasts;
  810. //
  811. // Set the WinsIsDown Flag and start a timer so we don't
  812. // try wins again for 15 seconds or so...only if we failed
  813. // to reach WINS, rather than WINS returning a neg response.
  814. //
  815. if (!(Flags & WINS_NEG_RESPONSE))
  816. {
  817. SetWinsDownFlag(pTracker->pDeviceContext);
  818. }
  819. }
  820. else
  821. {
  822. BOOLEAN bFound = FALSE;
  823. LOCATION(0x45);
  824. #ifdef MULTIPLE_WINS
  825. // Signal termination of WINs server queries
  826. pTracker->ResolutionContextFlags = NAME_RESOLUTION_DONE;
  827. #endif
  828. //
  829. // see if the name is in the lmhosts file, if it ISN'T the
  830. // proxy making the name query request!!
  831. //
  832. status = STATUS_UNSUCCESSFUL;
  833. //
  834. // In case the timer has been stopped, we coordinate
  835. // through the pClientCompletionRoutine Value with StopTimer.
  836. //
  837. pClientCompletion = pTimerQEntry->ClientCompletion;
  838. //
  839. // the timeout has expired on the broadcast name resolution
  840. // so call the client
  841. //
  842. //
  843. // remove from the PendingNameQueries list
  844. //
  845. RemoveEntryList(&pTracker->pNameAddr->Linkage);
  846. InitializeListHead(&pTracker->pNameAddr->Linkage);
  847. // remove the link from the name table to this timer block
  848. CHECK_PTR(((tNAMEADDR *)pTimerQEntry->pCacheEntry));
  849. ((tNAMEADDR *)pTimerQEntry->pCacheEntry)->pTimer = NULL;
  850. //
  851. // to synch. with the StopTimer routine, Null the client completion
  852. // routine so it gets called just once.
  853. //
  854. CHECK_PTR(pTimerQEntry);
  855. pTimerQEntry->ClientCompletion = NULL;
  856. if (((NbtConfig.EnableLmHosts) ||
  857. (NbtConfig.ResolveWithDns && !(pTracker->Flags & NO_DNS_RESOLUTION_FLAG))) &&
  858. (pTracker->pNameAddr->ProxyReqType == NAMEREQ_REGULAR))
  859. {
  860. // only do this if the client completion routine has not
  861. // been run yet.
  862. //
  863. if (pClientCompletion)
  864. {
  865. status = LmHostQueueRequest(pTracker,
  866. pTimerQEntry->ClientContext,
  867. pClientCompletion,
  868. pTracker->pDeviceContext);
  869. }
  870. }
  871. CHECK_PTR(pTimerQEntry);
  872. CHECK_PTR(pTimerQEntry->pCacheEntry);
  873. if (NT_SUCCESS(status))
  874. {
  875. // if it is successfully queued to the Worker thread,
  876. // then Null the ClientCompletion routine in the timerQ
  877. // structure, letting
  878. // the worker thread handle the rest of the name query
  879. // resolution. Also null the timer ptr in the
  880. // nameAddr entry in the name table.
  881. //
  882. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  883. }
  884. else
  885. {
  886. //
  887. // remove the name from the hash table, since it did not
  888. // resolve
  889. //
  890. CHECK_PTR(pTracker->pNameAddr);
  891. pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  892. pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
  893. pTracker->pNameAddr->pTimer = NULL;
  894. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  895. pTracker->pNameAddr = NULL;
  896. pClientTracker = (tDGRAM_SEND_TRACKING *)pTimerQEntry->ClientContext;
  897. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  898. // there can be a list of trackers Q'd up on this name
  899. // query, so we must complete all of them!
  900. //
  901. CompleteClientReq(pClientCompletion, pClientTracker, STATUS_TIMEOUT);
  902. // return the tracker block to its queue
  903. LOCATION(0x51);
  904. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  905. }
  906. return;
  907. }
  908. }
  909. LOCATION(0x48);
  910. NBT_REFERENCE_TRACKER(pTracker);
  911. pTimerQEntry->Flags |= TIMER_RESTART;
  912. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  913. status = UdpSendNSBcast(pTracker->pNameAddr,
  914. NbtConfig.pScope,
  915. pTracker,
  916. NULL,NULL,NULL,
  917. 0,0,
  918. eNAME_QUERY,
  919. TRUE);
  920. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  921. }
  922. //----------------------------------------------------------------------------
  923. VOID
  924. SetWinsDownFlag(
  925. tDEVICECONTEXT *pDeviceContext
  926. )
  927. /*++
  928. Routine Description:
  929. This routine sets the WinsIsDown flag if its not already set and
  930. its not a Bnode. It starts a 15 second or so timer that un sets the
  931. flag when it expires.
  932. This routine must be called while holding the Joint Lock.
  933. Arguments:
  934. None
  935. Return Value:
  936. None
  937. --*/
  938. {
  939. NTSTATUS status;
  940. tTIMERQENTRY *pTimer;
  941. if ((!pDeviceContext->WinsIsDown) && !(NodeType & BNODE))
  942. {
  943. status = StartTimer(WinsDownTimeout,
  944. NbtConfig.WinsDownTimeout,
  945. pDeviceContext, // context value
  946. NULL,
  947. NULL,
  948. NULL,
  949. pDeviceContext,
  950. &pTimer,
  951. 1, // retries
  952. TRUE);
  953. if (NT_SUCCESS(status))
  954. {
  955. pDeviceContext->WinsIsDown = TRUE;
  956. }
  957. }
  958. }
  959. //----------------------------------------------------------------------------
  960. VOID
  961. WinsDownTimeout(
  962. PVOID pContext,
  963. PVOID pContext2,
  964. tTIMERQENTRY *pTimerQEntry
  965. )
  966. /*++
  967. Routine Description:
  968. This routine is called by the timer code when the timer expires.
  969. It just sets the WinsIsDown boolean to False so that we will try WINS
  970. again. In this way we will avoid talking to WINS during this timeout.
  971. Arguments:
  972. Return Value:
  973. --*/
  974. {
  975. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pContext;
  976. CTELockHandle OldIrq;
  977. if (!pTimerQEntry)
  978. {
  979. return;
  980. }
  981. //
  982. // Hold the Joint Lock while traversing the list of devices
  983. //
  984. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  985. if (IsEntryInList (&pDeviceContext->Linkage, &NbtConfig.DeviceContexts))
  986. {
  987. pDeviceContext->WinsIsDown = FALSE;
  988. }
  989. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  990. IF_DBG(NBT_DEBUG_NAMESRV)
  991. KdPrint(("Nbt.WinsDownTimeout: WINS DOWN Timed Out - Up again\n"));
  992. }
  993. //----------------------------------------------------------------------------
  994. VOID
  995. CompleteClientReq(
  996. COMPLETIONCLIENT pClientCompletion,
  997. tDGRAM_SEND_TRACKING *pTracker,
  998. NTSTATUS status
  999. )
  1000. /*++
  1001. Routine Description:
  1002. This routine is called by completion routines to complete the client
  1003. request. It may involve completing several queued up requests.
  1004. Arguments:
  1005. Return Value:
  1006. The function value is the status of the operation.
  1007. --*/
  1008. {
  1009. PLIST_ENTRY pEntry;
  1010. tDGRAM_SEND_TRACKING *pTrack;
  1011. tDEVICECONTEXT *pDeviceContext;
  1012. CTELockHandle OldIrq;
  1013. LIST_ENTRY ListEntry;
  1014. InitializeListHead (&ListEntry);
  1015. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1016. //
  1017. // set up a new list head for any queued name queries.
  1018. // since we may need to do a new name query below.
  1019. // The Proxy hits this routine with a Null Tracker, so check for that.
  1020. //
  1021. if (pTracker)
  1022. {
  1023. pDeviceContext = pTracker->pDeviceContext;
  1024. if( !IsListEmpty(&pTracker->TrackerList))
  1025. {
  1026. ListEntry.Flink = pTracker->TrackerList.Flink;
  1027. ListEntry.Flink->Blink = &ListEntry;
  1028. ListEntry.Blink = pTracker->TrackerList.Blink;
  1029. ListEntry.Blink->Flink = &ListEntry;
  1030. InitializeListHead (&pTracker->TrackerList);
  1031. }
  1032. }
  1033. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1034. (*pClientCompletion)(pTracker,status);
  1035. while (!IsListEmpty(&ListEntry))
  1036. {
  1037. pEntry = RemoveHeadList(&ListEntry);
  1038. pTrack = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,TrackerList);
  1039. //
  1040. // if the name query failed and there is another requested queued on
  1041. // a different device context, re-attempt the name query
  1042. //
  1043. if ((pTrack->pDeviceContext != pDeviceContext) &&
  1044. (status != STATUS_SUCCESS))
  1045. {
  1046. //
  1047. // setup the correct back link since this guy is now the list
  1048. // head. The Flink is ok unless the list is empty now.
  1049. //
  1050. pTrack->TrackerList.Blink = ListEntry.Blink;
  1051. pTrack->TrackerList.Blink->Flink = &pTrack->TrackerList;
  1052. if (pTrack->TrackerList.Flink == &ListEntry)
  1053. {
  1054. pTrack->TrackerList.Flink = &pTrack->TrackerList;
  1055. }
  1056. // do a name query on the next name in the list
  1057. // and then wait for it to complete before processing any more
  1058. // names on the list.
  1059. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1060. status = QueryNameOnNet (pTrack->pDestName,
  1061. NbtConfig.pScope,
  1062. NBT_UNIQUE, //use this as the default
  1063. (PVOID)pTrack,
  1064. pTrack->CompletionRoutine,
  1065. NodeType & NODE_MASK,
  1066. NULL,
  1067. pTrack->pDeviceContext,
  1068. &OldIrq);
  1069. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1070. break;
  1071. }
  1072. else
  1073. {
  1074. //
  1075. // get the completion routine for this tracker since it may be
  1076. // different than the tracker tied to the timer block. i.e.
  1077. // pCompletionClient passed to this routine.
  1078. //
  1079. pClientCompletion = pTrack->CompletionRoutine;
  1080. (*pClientCompletion)(pTrack,status);
  1081. }
  1082. } // while
  1083. }
  1084. //----------------------------------------------------------------------------
  1085. NTSTATUS
  1086. NbtRegisterName(
  1087. IN enum eNbtLocation Location,
  1088. IN ULONG IpAddress,
  1089. IN PCHAR pName,
  1090. IN tNAMEADDR *pNameAddrIn,
  1091. IN tCLIENTELE *pClientEle,
  1092. IN PVOID pClientCompletion,
  1093. IN USHORT uAddressType,
  1094. IN tDEVICECONTEXT *pDeviceContext
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. This routine registers a name from local or from the network depending
  1099. on the value of Location. (i.e. local node uses this routine as well
  1100. as the proxy code.. although it has only been tested with the local
  1101. node registering names so far - and infact the remote code has been
  1102. removed... since it is not used. All that remains is to remove
  1103. the Location parameter.
  1104. Arguments:
  1105. Return Value:
  1106. NTSTATUS - success or not
  1107. --*/
  1108. {
  1109. ULONG Timeout;
  1110. USHORT Retries;
  1111. NTSTATUS status;
  1112. tNAMEADDR *pNameAddr;
  1113. USHORT uAddrType;
  1114. tDGRAM_SEND_TRACKING *pSentList= NULL;
  1115. CTELockHandle OldIrq1;
  1116. ULONG PrevNameTypeState;
  1117. ULONG LocalNodeType;
  1118. LocalNodeType = AppropriateNodeType( pName, NodeType );
  1119. if ((uAddressType == (USHORT)NBT_UNIQUE ) ||
  1120. (uAddressType == (USHORT)NBT_QUICK_UNIQUE))
  1121. {
  1122. uAddrType = NBT_UNIQUE;
  1123. }
  1124. else
  1125. {
  1126. uAddrType = NBT_GROUP;
  1127. }
  1128. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1129. if (IpAddress)
  1130. {
  1131. status = AddToHashTable (pNbtGlobConfig->pLocalHashTbl,
  1132. pName,
  1133. NbtConfig.pScope,
  1134. IpAddress,
  1135. uAddrType,
  1136. NULL,
  1137. &pNameAddr,
  1138. pDeviceContext,
  1139. 0);
  1140. if (status != STATUS_SUCCESS)
  1141. {
  1142. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1143. return(STATUS_UNSUCCESSFUL);
  1144. }
  1145. pNameAddr->RefreshMask = 0;
  1146. }
  1147. else
  1148. {
  1149. // in this case the name is already in the table, we just need
  1150. // to re-register it
  1151. //
  1152. status = FindInHashTable (pNbtGlobConfig->pLocalHashTbl, pName, NbtConfig.pScope, &pNameAddr);
  1153. if (!NT_SUCCESS(status))
  1154. {
  1155. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1156. return(status);
  1157. }
  1158. ASSERT (pNameAddr == pNameAddrIn);
  1159. }
  1160. CHECK_PTR(pNameAddr);
  1161. if ((uAddressType != (USHORT)NBT_UNIQUE ) &&
  1162. (uAddressType != (USHORT)NBT_QUICK_UNIQUE))
  1163. {
  1164. // this means group name so use Bcast Addr - UdpSendDgram changes this
  1165. // value to the Broadcast address of the particular adapter
  1166. // when is sees the 0. So when we send to a group name that is
  1167. // also registered on this node, it will go out as a broadcast
  1168. // to the subnet as well as to this node.
  1169. pNameAddr->IpAddress = 0;
  1170. }
  1171. #ifdef _NETBIOSLESS
  1172. if (IsDeviceNetbiosless(pDeviceContext)) // The Smb Device is not adapter specific
  1173. {
  1174. pNameAddr->NameFlags |= NAME_REGISTERED_ON_SMBDEV;
  1175. }
  1176. else
  1177. #endif
  1178. {
  1179. //
  1180. // start with the refreshed bit not set
  1181. //
  1182. pNameAddr->RefreshMask &= ~pDeviceContext->AdapterMask;
  1183. pNameAddr->AdapterMask |= pDeviceContext->AdapterMask; // turn on the adapter bit in the Mask
  1184. }
  1185. pClientEle->pAddress->pNameAddr = pNameAddr; // save the local name ptr in the address element
  1186. pNameAddr->pAddressEle = pClientEle->pAddress; // store a back ptr to the address element
  1187. pNameAddr->Ttl = NbtConfig.MinimumTtl; // set to 2 minutes until we hear differently from the Name Server
  1188. PrevNameTypeState = pNameAddr->NameTypeState;
  1189. pNameAddr->NameTypeState &= ~(NAME_TYPE_MASK | NAME_STATE_MASK);
  1190. pNameAddr->NameTypeState |= (uAddrType == NBT_UNIQUE) ? NAMETYPE_UNIQUE : NAMETYPE_GROUP;
  1191. if ((PrevNameTypeState & NAMETYPE_QUICK) ||
  1192. (uAddressType >= (USHORT)NBT_QUICK_UNIQUE))
  1193. {
  1194. pNameAddr->NameTypeState |= NAMETYPE_QUICK;
  1195. }
  1196. //
  1197. // for "quick" adds, do not register the name on the net!
  1198. // however the name will get registered with the name server and
  1199. // refreshed later....if this is an MS or M or P node.
  1200. //
  1201. if ((pNameAddr->NameTypeState & NAMETYPE_QUICK) ||
  1202. (pName[0] == '*') || // broadcast netbios name does not get claimed on network
  1203. (IpAddress == LOOP_BACK) || // If no IP address, pretend the registration succeeded
  1204. (pDeviceContext->IpAddress == 0) || // names will be registered when we get an address
  1205. (IsDeviceNetbiosless (pDeviceContext)))
  1206. {
  1207. pNameAddr->NameTypeState |= STATE_RESOLVED;
  1208. status = STATUS_SUCCESS;
  1209. }
  1210. else if (NT_SUCCESS(status = GetTracker(&pSentList, NBT_TRACKER_REGISTER_NAME)))
  1211. {
  1212. pNameAddr->NameTypeState |= STATE_RESOLVING;
  1213. InitializeListHead(&pSentList->Linkage); // there is no list of things sent yet
  1214. // keep a ptr to the name so we can update the state of the name
  1215. // later when the registration completes
  1216. pSentList->pNameAddr = pNameAddr;
  1217. pSentList->pDeviceContext = pDeviceContext;
  1218. pSentList->RefCount = 2; // tracker can be deref'ed by a pdu from wire before UdpSendNsBcast is done
  1219. #ifdef MULTIPLE_WINS
  1220. pSentList->NSOthersIndex = 0; // Initialize for Name Server Queries
  1221. pSentList->NSOthersLeft = 0;
  1222. #endif
  1223. // the code must now register the name on the network, depending on the type of node
  1224. Retries = pNbtGlobConfig->uNumBcasts + 1;
  1225. Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
  1226. pSentList->Flags = NBT_BROADCAST;
  1227. if (LocalNodeType & (PNODE | MSNODE))
  1228. {
  1229. // talk to the NS only to register the name
  1230. // ( the +1 does not actually result in a name reg, it
  1231. // is just compatible with the code for M node above since
  1232. // it uses the same completion routine).
  1233. //
  1234. Retries = (USHORT)pNbtGlobConfig->uNumRetries + 1;
  1235. Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
  1236. pSentList->Flags = NBT_NAME_SERVER;
  1237. //
  1238. // if there is no Primary WINS server short out the timeout
  1239. // so it completes faster. For Hnode this means to go broadcast.
  1240. //
  1241. if ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
  1242. pDeviceContext->WinsIsDown)
  1243. {
  1244. if (LocalNodeType & MSNODE)
  1245. {
  1246. pSentList->Flags = NBT_BROADCAST;
  1247. Retries = (USHORT)pNbtGlobConfig->uNumBcasts + 1;
  1248. Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
  1249. IncrementNameStats(NAME_REGISTRATION_SUCCESS, FALSE); // not name server register
  1250. }
  1251. else // its a Pnode
  1252. {
  1253. IF_DBG(NBT_DEBUG_NAMESRV)
  1254. KdPrint(("Nbt.NbtRegisterName: WINS DOWN - shorting out registration\n"));
  1255. Retries = 1;
  1256. Timeout = 10;
  1257. pSentList->Flags = NBT_NAME_SERVER_BACKUP;
  1258. }
  1259. }
  1260. }
  1261. // the name itself has a reference count too.
  1262. // make the count 2, so that pNameAddr won't get released until
  1263. // after NBT_DEREFERENCE_TRACKER is called below, since it writes to
  1264. // pNameAddr. Note that we must increment here rather than set = 2
  1265. // since it could be a multihomed machine doing the register at
  1266. // the same time we are sending a datagram to that name.
  1267. //
  1268. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_REGISTER);
  1269. pDeviceContext->DeviceRefreshState |= NBT_D_REFRESHING_NOW;
  1270. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1271. // start the timer in this routine.
  1272. status = UdpSendNSBcast(pNameAddr,
  1273. NbtConfig.pScope,
  1274. pSentList,
  1275. (PVOID) MSnodeRegCompletion,
  1276. pClientEle,
  1277. pClientCompletion,
  1278. Retries,
  1279. Timeout,
  1280. eNAME_REGISTRATION,
  1281. TRUE);
  1282. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1283. CHECK_PTR(pNameAddr);
  1284. NBT_DEREFERENCE_TRACKER (pSentList, TRUE); // possibly frees the tracker
  1285. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REGISTER, TRUE);
  1286. if (NT_SUCCESS(status))
  1287. {
  1288. status = STATUS_PENDING;
  1289. }
  1290. else // We failed to allocate resources, or the timer failed to start
  1291. {
  1292. IF_DBG(NBT_DEBUG_NAMESRV)
  1293. KdPrint(("Nbt.NbtRegisterName: UdpSendNsBcast returned ERROR = %x\n", status));
  1294. NbtTrace(NBT_TRACE_NAMESRV, ("UdpSendNSBcast return %!status! for %!NBTNAME!<%02x>",
  1295. status, pNameAddr->Name, (unsigned)pNameAddr->Name[15]));
  1296. NBT_DEREFERENCE_TRACKER (pSentList, TRUE);
  1297. }
  1298. }
  1299. if (!NT_SUCCESS(status))
  1300. {
  1301. if (!IsDeviceNetbiosless(pDeviceContext)) // The Smb Device is not adapter specific
  1302. {
  1303. pNameAddr->AdapterMask &= (~pDeviceContext->AdapterMask); // turn off the adapter bit in the Mask
  1304. }
  1305. pNameAddr->NameTypeState = PrevNameTypeState;
  1306. }
  1307. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1308. return(status);
  1309. }
  1310. //----------------------------------------------------------------------------
  1311. VOID
  1312. MSnodeRegCompletion(
  1313. PVOID pContext,
  1314. PVOID pContext2,
  1315. tTIMERQENTRY *pTimerQEntry
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. This routine is called by the timer code when the timer expires. It must
  1320. decide if another name registration should be done, and if not, then it calls the
  1321. client's completion routine (in completion2).
  1322. It first attempts to register a name via Broadcast, then it attempts
  1323. NameServer name registration.
  1324. Arguments:
  1325. Return Value:
  1326. The function value is the status of the operation.
  1327. --*/
  1328. {
  1329. NTSTATUS status;
  1330. tDGRAM_SEND_TRACKING *pTracker;
  1331. ULONG Flags;
  1332. CTELockHandle OldIrq;
  1333. enum eNSTYPE PduType;
  1334. ULONG LocalNodeType;
  1335. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  1336. PduType = eNAME_REGISTRATION;
  1337. LocalNodeType = AppropriateNodeType( pTracker->pNameAddr->Name, NodeType );
  1338. //
  1339. // check if the client completion routine is still set. If not then the
  1340. // timer has been cancelled and this routine should just clean up its
  1341. // buffers associated with the tracker.
  1342. //
  1343. if (!pTimerQEntry)
  1344. {
  1345. // return the tracker block to its queue
  1346. LOCATION(0x55);
  1347. pTracker->pNameAddr->pTimer = NULL;
  1348. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  1349. return;
  1350. }
  1351. //
  1352. // to prevent a client from stopping the timer and deleting the
  1353. // pNameAddr, grab the lock and check if the timer has been stopped
  1354. //
  1355. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1356. if (pTimerQEntry->Flags & TIMER_RETIMED)
  1357. {
  1358. pTimerQEntry->Flags &= ~TIMER_RETIMED;
  1359. pTimerQEntry->Flags |= TIMER_RESTART;
  1360. if ((!pTracker->pDeviceContext->IpAddress) ||
  1361. (pTracker->Flags & NBT_NAME_SERVER) &&
  1362. (pTracker->pDeviceContext->lNameServerAddress == LOOP_BACK))
  1363. {
  1364. // when the address is loop back there is no wins server
  1365. // so shorten the timeout.
  1366. //
  1367. pTimerQEntry->DeltaTime = 10;
  1368. }
  1369. else if ((pTracker->Flags & NBT_NAME_SERVER_BACKUP) &&
  1370. (pTracker->pDeviceContext->lBackupServer == LOOP_BACK))
  1371. {
  1372. // when the address is loop back there is no wins server
  1373. // so shorten the timeout.
  1374. //
  1375. pTimerQEntry->DeltaTime = 10;
  1376. }
  1377. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1378. return;
  1379. }
  1380. if (!pTimerQEntry->ClientCompletion)
  1381. {
  1382. NBT_DEREFERENCE_TRACKER(pTracker, TRUE); // Bug #: 230925
  1383. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1384. return;
  1385. }
  1386. // if number of retries is not zero then continue trying to contact the Name Server
  1387. //
  1388. if (--pTimerQEntry->Retries)
  1389. {
  1390. // change the name reg pdu to a name overwrite request for the
  1391. // final broadcast ( turn off Recursion Desired bit)
  1392. //
  1393. if (pTimerQEntry->Retries == 1)
  1394. {
  1395. if (pTracker->Flags & NBT_BROADCAST)
  1396. {
  1397. // do a broadcast name registration... on the last broadcast convert it to
  1398. // a Name OverWrite Request by clearing the "Recursion Desired" bit
  1399. // in the header
  1400. //
  1401. PduType = eNAME_REGISTRATION_OVERWRITE;
  1402. }
  1403. else if (LocalNodeType & (PNODE | MSNODE))
  1404. {
  1405. // we want the Pnode to timeout again, right away and fall
  1406. // through to handle Timed out name registration - i.e. it
  1407. // does not do the name overwrite demand like the B,M,&MS nodes
  1408. //
  1409. pTimerQEntry->Flags |= TIMER_RESTART;
  1410. pTimerQEntry->DeltaTime = 5;
  1411. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1412. return;
  1413. }
  1414. }
  1415. }
  1416. else
  1417. {
  1418. Flags = pTracker->Flags;
  1419. pTracker->Flags &= ~(NBT_BROADCAST | NBT_NAME_SERVER);
  1420. // set a different timeout for nameserver name registration
  1421. //
  1422. pTimerQEntry->DeltaTime = NbtConfig.uRetryTimeout;
  1423. pTimerQEntry->Retries = NbtConfig.uNumRetries + 1;
  1424. if ((Flags & NBT_BROADCAST) && (LocalNodeType & MNODE))
  1425. {
  1426. //
  1427. // Registered through broadcast, so try the name server now.
  1428. IncrementNameStats(NAME_REGISTRATION_SUCCESS, FALSE); // not name server register
  1429. pTracker->Flags |= NBT_NAME_SERVER;
  1430. if ((pTracker->pDeviceContext->lNameServerAddress == LOOP_BACK) ||
  1431. pTracker->pDeviceContext->WinsIsDown)
  1432. {
  1433. pTimerQEntry->DeltaTime = 10;
  1434. pTimerQEntry->Retries = 1;
  1435. }
  1436. }
  1437. else if ((Flags & NBT_NAME_SERVER) && !(LocalNodeType & BNODE))
  1438. {
  1439. //
  1440. // Can't reach the name server, so try the backup
  1441. pTracker->Flags |= NBT_NAME_SERVER_BACKUP;
  1442. //
  1443. // short out the timer if no backup server
  1444. //
  1445. if ((pTracker->pDeviceContext->lBackupServer == LOOP_BACK) ||
  1446. pTracker->pDeviceContext->WinsIsDown)
  1447. {
  1448. pTimerQEntry->DeltaTime = 10;
  1449. pTimerQEntry->Retries = 1;
  1450. }
  1451. }
  1452. else if ((LocalNodeType & MSNODE) && !(Flags & NBT_BROADCAST))
  1453. {
  1454. if (Flags & NBT_NAME_SERVER_BACKUP)
  1455. {
  1456. // the msnode switches to broadcast if all else fails
  1457. //
  1458. pTracker->Flags |= NBT_BROADCAST;
  1459. IncrementNameStats(NAME_REGISTRATION_SUCCESS, FALSE); // not name server register
  1460. //
  1461. // change the timeout and retries since broadcast uses a shorter timeout
  1462. //
  1463. pTimerQEntry->DeltaTime = NbtConfig.uBcastTimeout;
  1464. pTimerQEntry->Retries = (USHORT)pNbtGlobConfig->uNumBcasts + 1;
  1465. }
  1466. }
  1467. else
  1468. {
  1469. if (LocalNodeType & BNODE)
  1470. {
  1471. IncrementNameStats(NAME_REGISTRATION_SUCCESS, FALSE); // not name server register
  1472. }
  1473. //
  1474. // the timeout has expired on the name registration
  1475. // so call the client
  1476. //
  1477. // return the tracker block to its queue
  1478. LOCATION(0x54);
  1479. //
  1480. // start a timer to stop using WINS for a short period of
  1481. // time. Do this only if we had sent the last registration
  1482. // to a Wins server
  1483. //
  1484. if (!(Flags & NBT_BROADCAST) && pTracker->pDeviceContext->lNameServerAddress != LOOP_BACK)
  1485. {
  1486. SetWinsDownFlag(pTracker->pDeviceContext);
  1487. }
  1488. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  1489. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1490. status = STATUS_SUCCESS;
  1491. InterlockedCallCompletion(pTimerQEntry,status);
  1492. return;
  1493. }
  1494. }
  1495. NBT_REFERENCE_TRACKER (pTracker);
  1496. pTimerQEntry->Flags |= TIMER_RESTART;
  1497. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1498. status = UdpSendNSBcast(pTracker->pNameAddr,
  1499. NbtConfig.pScope,
  1500. pTracker,
  1501. NULL,NULL,NULL,
  1502. 0,0,
  1503. PduType,
  1504. TRUE);
  1505. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  1506. }
  1507. //----------------------------------------------------------------------------
  1508. VOID
  1509. RefreshRegCompletion(
  1510. PVOID pContext,
  1511. PVOID pContext2,
  1512. tTIMERQENTRY *pTimerQEntry
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This routine handles the name Refresh timeouts on packets sent to the Name
  1517. Service. I.e it sends refreshes to the nameserver until a response is
  1518. heard or the number of retries is exceeded.
  1519. Arguments:
  1520. Return Value:
  1521. The function value is the status of the operation.
  1522. --*/
  1523. {
  1524. NTSTATUS status;
  1525. tDGRAM_SEND_TRACKING *pTracker;
  1526. tNAMEADDR *pNameAddr;
  1527. CTELockHandle OldIrq;
  1528. COMPLETIONCLIENT pCompletionClient;
  1529. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  1530. if (!pTimerQEntry)
  1531. {
  1532. pTracker->pNameAddr->pTimer = NULL;
  1533. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  1534. return;
  1535. }
  1536. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1537. //
  1538. // check if the timer has been stopped yet, since stopping the timer
  1539. // nulls the client completion routine. If not null, increment the
  1540. // tracker refcount, so that the last refresh completing cannot
  1541. // free the tracker out from under us.
  1542. //
  1543. if (!(pCompletionClient = pTimerQEntry->ClientCompletion))
  1544. {
  1545. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  1546. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1547. return;
  1548. }
  1549. // if still some count left and not refreshed yet
  1550. // then do another refresh request
  1551. //
  1552. pNameAddr = pTracker->pNameAddr;
  1553. if (--pTimerQEntry->Retries)
  1554. {
  1555. NBT_REFERENCE_TRACKER (pTracker);
  1556. pTimerQEntry->Flags |= TIMER_RESTART;
  1557. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1558. status = UdpSendNSBcast(pTracker->pNameAddr,
  1559. NbtConfig.pScope,
  1560. pTracker,
  1561. NULL,NULL,NULL,
  1562. 0,0,
  1563. pTracker->AddressType,
  1564. TRUE);
  1565. // always restart even if the above send fails, since it might succeed
  1566. // later.
  1567. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  1568. }
  1569. else
  1570. {
  1571. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1572. // this calls the completion routine synchronizing with the
  1573. // timer expiry code.
  1574. InterlockedCallCompletion(pTimerQEntry,STATUS_TIMEOUT);
  1575. }
  1576. }
  1577. //----------------------------------------------------------------------------
  1578. NTSTATUS
  1579. ReleaseNameOnNet(
  1580. tNAMEADDR *pNameAddr,
  1581. PCHAR pScope,
  1582. PVOID pClientCompletion,
  1583. ULONG LocalNodeType,
  1584. tDEVICECONTEXT *pDeviceContext
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. This routine deletes a name on the network either by a
  1589. broadcast or by talking to the NS depending on the type of node. (M,P or B)
  1590. Arguments:
  1591. Return Value:
  1592. The function value is the status of the operation.
  1593. Called By: ProxyQueryFromNet() in proxy.c, NbtConnect() in name.c
  1594. --*/
  1595. {
  1596. ULONG Timeout;
  1597. USHORT Retries;
  1598. NTSTATUS status=STATUS_UNSUCCESSFUL;
  1599. tDGRAM_SEND_TRACKING *pTracker;
  1600. CTELockHandle OldIrq;
  1601. tTIMERQENTRY *pTimer;
  1602. status = GetTracker(&pTracker, NBT_TRACKER_RELEASE_NAME);
  1603. if (!NT_SUCCESS(status))
  1604. {
  1605. return(status);
  1606. }
  1607. pTracker->pDeviceContext = pDeviceContext;
  1608. pTracker->pNameAddr = pNameAddr;
  1609. pTracker->SendBuffer.pDgramHdr = NULL; // set to NULL to catch any erroneous frees.
  1610. pTracker->RefCount = 3; // We use the same tracker for the CompletionContext + Request
  1611. // Set a few values as a precursor to releasing the name either by
  1612. // broadcast or with the name server
  1613. //
  1614. LocalNodeType = AppropriateNodeType( pNameAddr->Name, LocalNodeType );
  1615. switch (LocalNodeType & NODE_MASK)
  1616. {
  1617. case MSNODE:
  1618. case MNODE:
  1619. case PNODE:
  1620. pTracker->Flags = NBT_NAME_SERVER;
  1621. Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
  1622. Retries = (USHORT)pNbtGlobConfig->uNumRetries;
  1623. break;
  1624. case BNODE:
  1625. default:
  1626. pTracker->Flags = NBT_BROADCAST;
  1627. Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
  1628. #ifndef VXD
  1629. Retries = (USHORT)pNbtGlobConfig->uNumBcasts;
  1630. #else
  1631. Retries = (USHORT)1;
  1632. #endif
  1633. }
  1634. //
  1635. // Release name on the network
  1636. //
  1637. IF_DBG(NBT_DEBUG_NAMESRV)
  1638. KdPrint(("Nbt.ReleaseNameOnNet: Doing Name Release on name %16.16s<%X>\n",
  1639. pNameAddr->Name,pNameAddr->Name[15]));
  1640. status = UdpSendNSBcast(pNameAddr,
  1641. pScope,
  1642. pTracker,
  1643. ReleaseCompletion,
  1644. pTracker,
  1645. pClientCompletion,
  1646. Retries,
  1647. Timeout,
  1648. eNAME_RELEASE,
  1649. TRUE);
  1650. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  1651. if (!NT_SUCCESS(status))
  1652. {
  1653. NTSTATUS Locstatus;
  1654. COMPLETIONCLIENT pCompletion;
  1655. PVOID pContext;
  1656. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1657. IF_DBG(NBT_DEBUG_NAMESRV)
  1658. KdPrint(("Nbt.ReleaseNameOnNet: UdpSendNSBcast failed - retcode = %X\n", status));
  1659. // Stopping the timer will call ReleaseCompletion which will
  1660. // free the tracker
  1661. //
  1662. pCompletion = NULL;
  1663. CHECK_PTR(pNameAddr);
  1664. if (pTimer = pNameAddr->pTimer)
  1665. {
  1666. pNameAddr->pTimer = NULL;
  1667. Locstatus = StopTimer(pTimer,&pCompletion,&pContext);
  1668. }
  1669. else
  1670. {
  1671. // no timer setup, so just free the tracker
  1672. //
  1673. FreeTracker(pTracker, RELINK_TRACKER);
  1674. }
  1675. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1676. }
  1677. return(status);
  1678. }
  1679. //----------------------------------------------------------------------------
  1680. VOID
  1681. ReleaseCompletion(
  1682. PVOID pContext,
  1683. PVOID pContext2,
  1684. tTIMERQENTRY *pTimerQEntry
  1685. )
  1686. /*++
  1687. Routine Description:
  1688. This routine is called by the timer code when the timer expires. It must
  1689. decide if another name query should be done, and if not, then it calls the
  1690. client's completion routine (in completion2).
  1691. This routine handles both the broadcast portion of the name queries and
  1692. the WINS server directed sends.
  1693. Arguments:
  1694. Return Value:
  1695. The function value is the status of the operation.
  1696. --*/
  1697. {
  1698. NTSTATUS status;
  1699. tDGRAM_SEND_TRACKING *pTracker;
  1700. ULONG LocalNodeType;
  1701. BOOLEAN fRetry;
  1702. CTELockHandle OldIrq;
  1703. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  1704. if (!pTimerQEntry)
  1705. {
  1706. pTracker->pNameAddr->pTimer = NULL;
  1707. NBT_DEREFERENCE_TRACKER (pTracker, TRUE);
  1708. return;
  1709. }
  1710. //
  1711. // There could be a scenario here where this name is currently being
  1712. // released, but we just got a new client with the same name -- in that
  1713. // case NbtOpenAddress will set the ReleaseMask to 0, so we stop
  1714. // releasing the name on that device if that happens!
  1715. //
  1716. if (!(pTracker->pNameAddr->ReleaseMask))
  1717. {
  1718. LocalNodeType = BNODE;
  1719. pTimerQEntry->Retries = 1;
  1720. }
  1721. else if (IsBrowserName(pTracker->pNameAddr->Name))
  1722. {
  1723. LocalNodeType = BNODE;
  1724. }
  1725. else
  1726. {
  1727. LocalNodeType = NodeType;
  1728. }
  1729. fRetry = TRUE;
  1730. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1731. if (IsEntryInList (&pTracker->pDeviceContext->Linkage, &NbtConfig.DeviceContexts))
  1732. {
  1733. // if number of retries is not zero then continue trying
  1734. // to contact the Name Server.
  1735. //
  1736. if (!(--pTimerQEntry->Retries))
  1737. {
  1738. if ((LocalNodeType & MNODE) &&
  1739. (pTracker->Flags & NBT_NAME_SERVER))
  1740. {
  1741. //
  1742. // try broadcast
  1743. //
  1744. pTracker->Flags &= ~NBT_NAME_SERVER;
  1745. pTracker->Flags |= NBT_BROADCAST;
  1746. // set a different timeout for broadcast name resolution
  1747. //
  1748. pTimerQEntry->DeltaTime = NbtConfig.uBcastTimeout;
  1749. pTimerQEntry->Retries = NbtConfig.uNumBcasts;
  1750. }
  1751. else
  1752. {
  1753. fRetry = FALSE;
  1754. }
  1755. }
  1756. }
  1757. else
  1758. {
  1759. fRetry = FALSE;
  1760. }
  1761. #ifdef VXD
  1762. if (fRetry)
  1763. #else
  1764. if ((fRetry) &&
  1765. (NBT_REFERENCE_DEVICE (pTracker->pDeviceContext, REF_DEV_NAME_REL, TRUE)))
  1766. #endif // VXD
  1767. {
  1768. NBT_REFERENCE_TRACKER (pTracker);
  1769. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1770. status = UdpSendNSBcast(pTracker->pNameAddr,
  1771. NbtConfig.pScope,
  1772. pTracker,
  1773. NULL,NULL,NULL,
  1774. 0,0,
  1775. eNAME_RELEASE,
  1776. TRUE);
  1777. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1778. #ifndef VXD
  1779. NBT_DEREFERENCE_DEVICE (pTracker->pDeviceContext, REF_DEV_NAME_REL, TRUE);
  1780. #endif !VXD
  1781. NBT_DEREFERENCE_TRACKER (pTracker, TRUE);
  1782. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1783. pTimerQEntry->Flags |= TIMER_RESTART;
  1784. return;
  1785. }
  1786. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1787. //
  1788. // the timeout has expired on the name release
  1789. // or the Device on which we were releasing the name
  1790. // could have gone away, so call the client
  1791. //
  1792. status = InterlockedCallCompletion(pTimerQEntry,STATUS_TIMEOUT);
  1793. // return the tracker block to its queue if we successfully
  1794. // called the completion routine since someone else might
  1795. // have done a Stop timer at this very moment and freed the
  1796. // tracker already (i.e. the last else clause in this routine).
  1797. //
  1798. if (NT_SUCCESS(status))
  1799. {
  1800. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  1801. }
  1802. }
  1803. //----------------------------------------------------------------------------
  1804. VOID
  1805. NameReleaseDone(
  1806. PVOID pContext,
  1807. NTSTATUS Status
  1808. )
  1809. /*++
  1810. Routine Description:
  1811. This routine is called when a name is released on the network. Its
  1812. main, role in life is to free the memory in Context, which is the pAddressEle
  1813. structure.
  1814. Arguments:
  1815. Return Value:
  1816. The function value is the status of the operation.
  1817. Called By Release Completion (above)
  1818. --*/
  1819. {
  1820. CTELockHandle OldIrq1;
  1821. tDEVICECONTEXT *pDeviceContext;
  1822. tDGRAM_SEND_TRACKING *pTracker = (tDGRAM_SEND_TRACKING *) pContext;
  1823. tNAMEADDR *pNameAddr = pTracker->pNameAddr;
  1824. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1825. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  1826. pNameAddr->pTimer = NULL; // Since we could be starting a new Timer below
  1827. //
  1828. // Before releasing this name, see if this name is registered on
  1829. // any more devices
  1830. // WARNING -- Do not touch the current pTracker->DeviceContext since the
  1831. // the device may have gone away
  1832. //
  1833. while (pDeviceContext = GetAndRefNextDeviceFromNameAddr (pNameAddr))
  1834. {
  1835. //
  1836. // Increment the RefCounts for the structures we need to keep around
  1837. // They will be Dereferenced when the Name Release has completed
  1838. //
  1839. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1840. Status = ReleaseNameOnNet(pNameAddr,
  1841. NbtConfig.pScope,
  1842. NameReleaseDone,
  1843. NodeType,
  1844. pDeviceContext);
  1845. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1846. #ifndef VXD
  1847. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_GET_REF, TRUE);
  1848. #endif // !VXD
  1849. if (NT_SUCCESS(Status))
  1850. {
  1851. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1852. return;
  1853. }
  1854. //
  1855. // We failed to release the name on this Device, so try the
  1856. // next Device!
  1857. //
  1858. }
  1859. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_RELEASE, TRUE);
  1860. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1861. }
  1862. //----------------------------------------------------------------------------
  1863. NTSTATUS
  1864. StartRefresh(
  1865. IN tNAMEADDR *pNameAddr,
  1866. IN tDGRAM_SEND_TRACKING *pTracker,
  1867. IN CTELockHandle *pJointLockOldIrq,
  1868. IN BOOLEAN ResetDevice
  1869. )
  1870. /*++
  1871. Routine Description:
  1872. This routine handles refreshing a name with the Name server.
  1873. The idea is to set the timeout to T/8 and check for names with the Refresh
  1874. bit cleared - re-registering those names. At T=4 and T=0, clear all bits
  1875. and refresh all names. The Inbound code sets the refresh bit when it gets a
  1876. refresh response from the NS.
  1877. The JointLock is held while this routine is called, and the last Irql is
  1878. passed in pJointLockOldIrq
  1879. Arguments:
  1880. Return Value:
  1881. none
  1882. --*/
  1883. {
  1884. NTSTATUS status;
  1885. tDEVICECONTEXT *pDeviceContext = NULL;
  1886. BOOLEAN NewTracker = FALSE;
  1887. if (!pTracker)
  1888. {
  1889. LOCATION(0x9);
  1890. status = GetTracker(&pTracker, NBT_TRACKER_REFRESH_NAME);
  1891. if (!NT_SUCCESS(status))
  1892. {
  1893. return(STATUS_INSUFFICIENT_RESOURCES);
  1894. }
  1895. // need to prevent the tracker from being freed by a pdu from
  1896. // the wire before the UdpSendNsBcast is done
  1897. //
  1898. pTracker->RefCount = 1;
  1899. NewTracker = TRUE;
  1900. }
  1901. // set the name to be refreshed in the tracker block
  1902. pTracker->pNameAddr = pNameAddr;
  1903. // this is set true when a new name gets refreshed
  1904. //
  1905. if ((ResetDevice) || (NewTracker))
  1906. {
  1907. PLIST_ENTRY pEntry, pHead;
  1908. CTEULONGLONG AdapterMask;
  1909. LOCATION(0xb);
  1910. //
  1911. // Identify the Adapters which have not been refreshed
  1912. // Then, get the lowest Adapter number and Refresh on it
  1913. //
  1914. pHead = &NbtConfig.DeviceContexts;
  1915. AdapterMask = pNameAddr->AdapterMask & ~(pNameAddr->RefreshMask);
  1916. AdapterMask = ~(AdapterMask - 1) & AdapterMask;
  1917. ASSERT (AdapterMask);
  1918. while (AdapterMask)
  1919. {
  1920. //
  1921. // Travel to the actual device for this Adapter number
  1922. //
  1923. pEntry = pHead->Flink;
  1924. while (pEntry != pHead)
  1925. {
  1926. pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  1927. if (pDeviceContext->AdapterMask == AdapterMask)
  1928. {
  1929. //
  1930. // Found a valid device on which this name is registered
  1931. //
  1932. break;
  1933. }
  1934. else
  1935. {
  1936. pDeviceContext = NULL;
  1937. }
  1938. //
  1939. // Go to next device
  1940. //
  1941. pEntry = pEntry->Flink;
  1942. }
  1943. if (pDeviceContext)
  1944. {
  1945. //
  1946. // Found a Device to do a NameRefresh on
  1947. //
  1948. break;
  1949. }
  1950. //
  1951. // This is an error case -- the device for this adapter number
  1952. // does not exist. Remove it from the Adapter and Refresh masks
  1953. //
  1954. pNameAddr->AdapterMask &= ~AdapterMask;
  1955. pNameAddr->RefreshMask &= ~AdapterMask;
  1956. AdapterMask = pNameAddr->AdapterMask & ~(pNameAddr->RefreshMask);
  1957. AdapterMask = ~(AdapterMask - 1) & AdapterMask;
  1958. }
  1959. if (!pDeviceContext)
  1960. {
  1961. IF_DBG(NBT_DEBUG_REFRESH)
  1962. KdPrint(("Nbt.StartRefresh: Failed to Refresh <%16.16s:%x>!! no valid adapter ****\n",
  1963. pNameAddr->Name, pNameAddr->Name[15]));
  1964. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  1965. return(STATUS_UNSUCCESSFUL);
  1966. }
  1967. #ifndef VXD
  1968. IF_DBG(NBT_DEBUG_REFRESH)
  1969. KdPrint(("Nbt.StartRefresh: Refresh adapter: %lx:%lx, dev.nm: %lx for name: %lx\n",
  1970. AdapterMask, pDeviceContext->BindName.Buffer, pNameAddr));
  1971. #endif // !VXD
  1972. pTracker->pDeviceContext = pDeviceContext;
  1973. //
  1974. // Clear the transaction Id so that CreatePdu will increment
  1975. // it for this new name
  1976. //
  1977. CHECK_PTR(pTracker);
  1978. pTracker->TransactionId = 0;
  1979. }
  1980. pTracker->pDeviceContext->DeviceRefreshState |= NBT_D_REFRESHING_NOW;
  1981. pDeviceContext = pTracker->pDeviceContext;
  1982. pTracker->AddressType = eNAME_REFRESH;
  1983. // Check if we need to refresh to the primary or backup
  1984. if ((pDeviceContext->IpAddress) &&
  1985. (pTracker->pDeviceContext->lNameServerAddress == LOOP_BACK) &&
  1986. (pNameAddr->NameTypeState & STATE_CONFLICT) &&
  1987. (!pNameAddr->ConflictMask))
  1988. {
  1989. //
  1990. // Broadcast the Refresh to ensure no conflict
  1991. //
  1992. pTracker->Flags = NBT_BROADCAST;
  1993. pTracker->AddressType = eNAME_REGISTRATION;
  1994. }
  1995. else if (pTracker->pDeviceContext->RefreshToBackup)
  1996. {
  1997. pTracker->Flags = NBT_NAME_SERVER_BACKUP;
  1998. }
  1999. else
  2000. {
  2001. pTracker->Flags = NBT_NAME_SERVER;
  2002. }
  2003. // this accounts for the dereference done after the call to
  2004. // send the datagram below.
  2005. NBT_REFERENCE_TRACKER (pTracker);
  2006. CTESpinFree(&NbtConfig.JointLock,*pJointLockOldIrq);
  2007. status = UdpSendNSBcast(pNameAddr,
  2008. NbtConfig.pScope,
  2009. pTracker,
  2010. RefreshRegCompletion,
  2011. pTracker,
  2012. NextRefresh,
  2013. NbtConfig.uNumRetries,
  2014. NbtConfig.uRetryTimeout,
  2015. pTracker->AddressType,
  2016. TRUE);
  2017. CTESpinLock(&NbtConfig.JointLock,*pJointLockOldIrq);
  2018. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  2019. LOCATION(0x57);
  2020. if (!NT_SUCCESS(status))
  2021. {
  2022. LOCATION(0xe);
  2023. IF_DBG(NBT_DEBUG_REFRESH)
  2024. KdPrint(("Nbt.StartRefresh: Failed to send Refresh!! status = %X****\n",status));
  2025. //
  2026. // This will free the tracker. Name refresh will stop until
  2027. // the next refresh timeout and at that point it will attempt
  2028. // to refresh the names again.
  2029. //
  2030. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  2031. }
  2032. return(status);
  2033. }
  2034. //----------------------------------------------------------------------------
  2035. VOID
  2036. GetNextName(
  2037. IN tNAMEADDR *pNameAddrIn,
  2038. OUT tNAMEADDR **ppNameAddr
  2039. )
  2040. /*++
  2041. Routine Description:
  2042. This routine finds the next name to refresh, including incrementing the
  2043. reference count so that the name cannot be deleted during the refresh.
  2044. The JointLock spin lock is held before calling this routine.
  2045. Arguments:
  2046. Return Value:
  2047. none
  2048. --*/
  2049. {
  2050. PLIST_ENTRY pHead;
  2051. PLIST_ENTRY pEntry;
  2052. LONG i, iIndex;
  2053. tNAMEADDR *pNameAddr;
  2054. tHASHTABLE *pHashTable;
  2055. pHashTable = NbtConfig.pLocalHashTbl;
  2056. for (i= NbtConfig.CurrentHashBucket;i < pHashTable->lNumBuckets ;i++ )
  2057. {
  2058. //
  2059. // use the last name as the current position in the linked list
  2060. // only if that name is still resolved, otherwise start at the
  2061. // begining of the hash list, incase the name got deleted in the
  2062. // mean time.
  2063. //
  2064. if (pNameAddrIn)
  2065. {
  2066. //
  2067. // The Address for this name is Referenced, so it has to be a valid name!
  2068. //
  2069. ASSERT (NBT_VERIFY_HANDLE (pNameAddrIn, LOCAL_NAME));
  2070. if ((pNameAddrIn->NameTypeState & STATE_CONFLICT) &&
  2071. (!pNameAddrIn->ConflictMask) &&
  2072. (!(pNameAddrIn->NameTypeState & REFRESH_FAILED)))
  2073. {
  2074. //
  2075. // If we succeeded in Refreshing on all adapters,
  2076. // remove the name from the Conflict state
  2077. //
  2078. pNameAddrIn->NameTypeState &= (~NAME_STATE_MASK);
  2079. pNameAddrIn->NameTypeState |= STATE_RESOLVED;
  2080. }
  2081. // first hash the name to an index
  2082. // take the lower nibble of the first 2 characters.. mod table size
  2083. iIndex = ((pNameAddrIn->Name[0] & 0x0F) << 4) + (pNameAddrIn->Name[1] & 0x0F);
  2084. iIndex = iIndex % pHashTable->lNumBuckets;
  2085. if (iIndex != NbtConfig.CurrentHashBucket)
  2086. {
  2087. //
  2088. // Someone else is refreshing right now!
  2089. //
  2090. *ppNameAddr = NULL;
  2091. return;
  2092. }
  2093. pHead = &NbtConfig.pLocalHashTbl->Bucket[NbtConfig.CurrentHashBucket];
  2094. pEntry = pNameAddrIn->Linkage.Flink;
  2095. pNameAddrIn = NULL;
  2096. }
  2097. else
  2098. {
  2099. pHead = &pHashTable->Bucket[i];
  2100. pEntry = pHead->Flink;
  2101. }
  2102. while (pEntry != pHead)
  2103. {
  2104. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  2105. pEntry = pEntry->Flink;
  2106. // don't refresh scope names or names in conflict or that are the
  2107. // broadcast name "* " or quick unique names - i.e. the permanent
  2108. // name is nametype quick
  2109. //
  2110. if ((pNameAddr->Name[0] != '*') &&
  2111. (!(pNameAddr->NameTypeState & NAMETYPE_QUICK)) &&
  2112. (pNameAddr->pAddressEle) && // Not currently being closed down!
  2113. ((pNameAddr->NameTypeState & STATE_RESOLVED) ||
  2114. ((pNameAddr->NameTypeState & STATE_CONFLICT) && (!pNameAddr->ConflictMask))))
  2115. {
  2116. // check if the name has been refreshed yet
  2117. //
  2118. // Refresh this name only if any of the non-refreshed bits in
  2119. // the RefreshMask match any of the bits for the adapters this
  2120. // device is registered on!
  2121. pNameAddr->NameTypeState &= (~REFRESH_FAILED); // Will be set on Failure
  2122. if (pNameAddr->AdapterMask & ~pNameAddr->RefreshMask)
  2123. {
  2124. // increment the reference count so that this name cannot
  2125. // disappear while it is being refreshed and mess up the linked list
  2126. NBT_REFERENCE_ADDRESS (pNameAddr->pAddressEle, REF_ADDR_REFRESH);
  2127. NbtConfig.CurrentHashBucket = (USHORT)i;
  2128. *ppNameAddr = pNameAddr;
  2129. return;
  2130. }
  2131. else if (pNameAddr->NameTypeState & STATE_CONFLICT)
  2132. {
  2133. pNameAddr->NameTypeState &= (~NAME_STATE_MASK);
  2134. pNameAddr->NameTypeState |= STATE_RESOLVED;
  2135. }
  2136. }
  2137. }
  2138. }
  2139. *ppNameAddr = NULL;
  2140. }
  2141. //----------------------------------------------------------------------------
  2142. VOID
  2143. NextRefresh(
  2144. IN PVOID pContext,
  2145. IN NTSTATUS CompletionStatus
  2146. )
  2147. /*++
  2148. Routine Description:
  2149. This routine queues the work to an Executive worker thread to handle
  2150. refreshing the next name.
  2151. Arguments:
  2152. Return Value:
  2153. none
  2154. --*/
  2155. {
  2156. tDGRAM_SEND_TRACKING *pTracker;
  2157. CTELockHandle OldIrq;
  2158. pTracker = (tDGRAM_SEND_TRACKING *) pContext;
  2159. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2160. pTracker->pNameAddr->pTimer = NULL; // Set the timer to NULL!
  2161. if (!(NBT_VERIFY_HANDLE (pTracker->pDeviceContext, NBT_VERIFY_DEVCONTEXT)))
  2162. {
  2163. //
  2164. // Since the Device is going away, let's assume we succeeded
  2165. //
  2166. CompletionStatus = STATUS_SUCCESS;
  2167. pTracker->pDeviceContext = NULL;
  2168. }
  2169. if (!NT_SUCCESS(CTEQueueForNonDispProcessing (DelayedNextRefresh,
  2170. pTracker,
  2171. ULongToPtr(CompletionStatus), // Sundown: zero-extended.
  2172. NULL,
  2173. pTracker->pDeviceContext,
  2174. TRUE)))
  2175. {
  2176. IF_DBG(NBT_DEBUG_REFRESH)
  2177. KdPrint (("Nbt.NextRefresh: Failed to Enqueu DelayedNextRefresh!!!\n"));
  2178. NBT_DEREFERENCE_TRACKER (pTracker, TRUE);
  2179. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  2180. }
  2181. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2182. }
  2183. //----------------------------------------------------------------------------
  2184. VOID
  2185. DelayedNextRefresh(
  2186. IN tDGRAM_SEND_TRACKING *pTracker,
  2187. IN PVOID pClientContext,
  2188. IN PVOID pUnused1,
  2189. IN tDEVICECONTEXT *pDeviceContext
  2190. )
  2191. /*++
  2192. Routine Description:
  2193. This routine handles sending subsequent refreshes to the name server.
  2194. This is the "Client Completion" routine of the Timer started above.
  2195. Arguments:
  2196. Return Value:
  2197. none
  2198. --*/
  2199. {
  2200. CTELockHandle OldIrq;
  2201. tNAMEADDR *pNameAddr;
  2202. tNAMEADDR *pNameAddrNext;
  2203. NTSTATUS status;
  2204. PLIST_ENTRY pEntry, pHead;
  2205. CTEULONGLONG AdapterMask;
  2206. BOOLEAN fAbleToReachWins = FALSE;
  2207. BOOLEAN fResetDevice = FALSE;
  2208. NTSTATUS CompletionStatus;
  2209. CompletionStatus = (NTSTATUS) (ULONG_PTR) pClientContext;
  2210. pNameAddr = pTracker->pNameAddr;
  2211. ASSERT(pNameAddr);
  2212. //
  2213. // grab the resource so that a name refresh response cannot start running this
  2214. // code in a different thread before this thread has exited this routine,
  2215. // otherwise the tracker can get dereferenced twice and blown away.
  2216. //
  2217. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  2218. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2219. LOCATION(0x1);
  2220. // turn on the bit corresponding to this adapter, since the name refresh
  2221. // completed ok
  2222. //
  2223. if (CompletionStatus == STATUS_SUCCESS)
  2224. {
  2225. if (pDeviceContext)
  2226. {
  2227. //
  2228. // turn on the bit corresponding to this adapter, since the name refresh
  2229. // completed ok
  2230. //
  2231. pNameAddr->RefreshMask |= pDeviceContext->AdapterMask;
  2232. }
  2233. fAbleToReachWins = TRUE;
  2234. }
  2235. else if (CompletionStatus == STATUS_TIMEOUT)
  2236. {
  2237. if (pNameAddr->NameTypeState & STATE_CONFLICT)
  2238. {
  2239. if ((!pDeviceContext->IpAddress) ||
  2240. (pDeviceContext->lNameServerAddress == LOOP_BACK))
  2241. {
  2242. //
  2243. // Let us assume we succeeded
  2244. fAbleToReachWins = TRUE;
  2245. }
  2246. else
  2247. {
  2248. pNameAddr->NameTypeState |= REFRESH_FAILED;
  2249. }
  2250. }
  2251. }
  2252. else // CompletionStatus != STATUS_TIMEOUT
  2253. {
  2254. LOCATION(0x3);
  2255. // if the timer times out and we did not get to the name server, then
  2256. // that is not an error. However, any other bad status
  2257. // must be a negative response to a name refresh so mark the name
  2258. // in conflict
  2259. //
  2260. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  2261. pNameAddr->NameTypeState |= STATE_CONFLICT;
  2262. pNameAddr->ConflictMask |= pDeviceContext->AdapterMask;
  2263. fAbleToReachWins = TRUE;
  2264. }
  2265. // for the multihomed case a failure to reach wins out one of the adapters
  2266. // is not necessarily a failure to reach any WINS. Since this flag
  2267. // is just an optimization to prevent clients from continually trying to
  2268. // register all of their names if WINS is unreachable, we can ignore the
  2269. // optimization for the multihomed case. The few nodes that are
  2270. // multihomed will not create that much traffic compared to possibly
  2271. // thousands that are singly homed clients.
  2272. if (NbtConfig.MultiHomed)
  2273. {
  2274. fAbleToReachWins = TRUE;
  2275. }
  2276. LOCATION(0x8);
  2277. //
  2278. // still more adapters to check ...
  2279. //
  2280. // go to the next device context and refresh the name there
  2281. // using the same tracker.
  2282. // look for a device context with a valid IP address since there is
  2283. // no sense in refreshing names out unconnected RAS links.
  2284. //
  2285. if (pDeviceContext)
  2286. {
  2287. //
  2288. // check if any higher bits are set inthe AdapterMask
  2289. //
  2290. AdapterMask = pTracker->pDeviceContext->AdapterMask;
  2291. AdapterMask = AdapterMask << 1;
  2292. pDeviceContext = NULL;
  2293. }
  2294. else
  2295. {
  2296. //
  2297. // The Device we were Refreshing on has gone away, but we don't
  2298. // know which one it was, so ReRefresh!
  2299. //
  2300. AdapterMask = 1;
  2301. }
  2302. //
  2303. // If we have finished refreshing on all devices for this name, get the next name
  2304. //
  2305. if ( (!(AdapterMask) ||
  2306. (AdapterMask > (pNameAddr->AdapterMask & ~pNameAddr->RefreshMask))) )
  2307. {
  2308. // *** clean up the previously refreshed name ***
  2309. // if we failed to reach WINS on the last refresh, stop refreshing
  2310. // until the next time interval. This cuts down on network traffic.
  2311. //
  2312. if (fAbleToReachWins)
  2313. {
  2314. GetNextName(pNameAddr,&pNameAddrNext);
  2315. AdapterMask = 1;
  2316. fResetDevice = TRUE;
  2317. }
  2318. else
  2319. {
  2320. pNameAddrNext = NULL;
  2321. }
  2322. //
  2323. // Dereference the previous address after calling GetNextName
  2324. // since it cause the Name to get free'ed
  2325. //
  2326. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2327. NBT_DEREFERENCE_ADDRESS (pNameAddr->pAddressEle, REF_ADDR_REFRESH);
  2328. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2329. pNameAddr = pNameAddrNext;
  2330. }
  2331. pHead = &NbtConfig.DeviceContexts;
  2332. while (pNameAddr)
  2333. {
  2334. //
  2335. // Get mask of Adapters left to Refresh on; after that, get the lowest adapter number
  2336. //
  2337. AdapterMask = ~(AdapterMask-1) & (pNameAddr->AdapterMask & ~(pNameAddr->RefreshMask));
  2338. AdapterMask &= ~(AdapterMask - 1);
  2339. //
  2340. // Travel to the actual device for this Adapter number
  2341. //
  2342. pEntry = pHead->Flink;
  2343. while (pEntry != pHead)
  2344. {
  2345. pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  2346. //
  2347. // Check if this Device matches the AdapterMask and also has
  2348. // a valid ip address and name server address
  2349. //
  2350. if (pDeviceContext->AdapterMask == AdapterMask)
  2351. {
  2352. if ((pDeviceContext->IpAddress != 0) &&
  2353. ((pDeviceContext->lNameServerAddress != LOOP_BACK)) ||
  2354. ((pNameAddr->NameTypeState & STATE_CONFLICT) && (!pNameAddr->ConflictMask)))
  2355. {
  2356. //
  2357. // Found a valid device on which this name is registered
  2358. //
  2359. IF_DBG(NBT_DEBUG_REFRESH)
  2360. KdPrint(("Nbt.DelayedNextRefresh: Adapter <%lx:%lx>, Name <%15.15s:%X>\n",
  2361. AdapterMask,pNameAddr->Name,pNameAddr->Name[15]));
  2362. pTracker->pDeviceContext = pDeviceContext;
  2363. // remove the previous timer from the AddressEle since StartRefresh
  2364. // will start a new timer - safety measure and probably not required!
  2365. //
  2366. CHECK_PTR(pNameAddr);
  2367. pNameAddr->pTimer = NULL;
  2368. // this call sends out a name registration PDU on a different adapter
  2369. // to (potentially) a different name server. The Name service PDU
  2370. // is the same as the last one though...no need to create a new one.
  2371. //
  2372. status = StartRefresh(pNameAddr, pTracker, &OldIrq, fResetDevice);
  2373. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2374. if (!NT_SUCCESS(status))
  2375. {
  2376. NBT_DEREFERENCE_ADDRESS (pNameAddr->pAddressEle, REF_ADDR_REFRESH);
  2377. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  2378. KdPrint(("Nbt.DelayedNextRefresh: ERROR -- Refreshing <%-15.15s:%x>, status=<%X>\n",
  2379. pNameAddr->Name,pNameAddr->Name[15], status));
  2380. }
  2381. goto ExitRoutine;
  2382. }
  2383. //
  2384. // This Device from AdapterMask did not have a valid IP or WINS address
  2385. //
  2386. break;
  2387. }
  2388. else
  2389. {
  2390. pDeviceContext = NULL;
  2391. }
  2392. //
  2393. // Go to next device
  2394. //
  2395. pEntry = pEntry->Flink;
  2396. }
  2397. //
  2398. // If we reached here with a non-NULL pDeviceContext, then it means that
  2399. // the Device did not have a valid IP address or Name Server address
  2400. // otherwise ...
  2401. //
  2402. if (!pDeviceContext)
  2403. {
  2404. //
  2405. //
  2406. // Error case:
  2407. // It could be that an adapter was removed while we were looping
  2408. //
  2409. KdPrint (("Nbt.DelayedNextRefresh: AdapterMask <%lx:%lx> no longer exists!\n", AdapterMask));
  2410. pNameAddr->AdapterMask &= ~AdapterMask;
  2411. pNameAddr->RefreshMask &= ~AdapterMask;
  2412. }
  2413. //
  2414. // Go to the next adapter
  2415. //
  2416. AdapterMask = AdapterMask << 1;
  2417. //
  2418. // Check if this name has any more adapters on which it can be refreshed
  2419. //
  2420. if ( (!(AdapterMask) ||
  2421. (AdapterMask > (pNameAddr->AdapterMask & ~pNameAddr->RefreshMask))) )
  2422. {
  2423. // *** clean up the previously refreshed name ***
  2424. if (fAbleToReachWins)
  2425. {
  2426. //
  2427. // No more adapters on which to Refresh for the previous name
  2428. // Get the next name in the hash table
  2429. //
  2430. GetNextName(pNameAddr,&pNameAddrNext);
  2431. AdapterMask = 1;
  2432. fResetDevice = TRUE;
  2433. pHead = &NbtConfig.DeviceContexts;
  2434. }
  2435. else
  2436. {
  2437. pNameAddrNext = NULL;
  2438. }
  2439. //
  2440. // Dereference the previous address after calling GetNextName
  2441. // since it cause the Name to get free'ed
  2442. //
  2443. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2444. NBT_DEREFERENCE_ADDRESS (pNameAddr->pAddressEle, REF_ADDR_REFRESH);
  2445. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2446. pNameAddr = pNameAddrNext;
  2447. }
  2448. }
  2449. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2450. if (!pNameAddr)
  2451. {
  2452. LOCATION(0x7);
  2453. // we finally delete the tracker here after using it to refresh
  2454. // all of the names. It is not deleted in the RefreshCompletion
  2455. // routine anymore!
  2456. //
  2457. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  2458. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  2459. }
  2460. ExitRoutine:
  2461. CTEExReleaseResource(&NbtConfig.Resource);
  2462. }
  2463. //----------------------------------------------------------------------------
  2464. VOID
  2465. WakeupRefreshTimeout(
  2466. PVOID pContext,
  2467. PVOID pContext2,
  2468. tTIMERQENTRY *pTimerQEntry
  2469. )
  2470. {
  2471. if (NbtConfig.pWakeupRefreshTimer)
  2472. {
  2473. NbtConfig.pWakeupRefreshTimer = NULL;
  2474. ReRegisterLocalNames (NULL, FALSE);
  2475. }
  2476. }
  2477. //----------------------------------------------------------------------------
  2478. VOID
  2479. RefreshTimeout(
  2480. PVOID pContext,
  2481. PVOID pContext2,
  2482. tTIMERQENTRY *pTimerQEntry
  2483. )
  2484. /*++
  2485. Routine Description:
  2486. This routine handles is the timeout handler for name refreshes to
  2487. WINS. It just queues the request to the Executive worker thread so that
  2488. the work can be done at non-dispatch level. If there is currently a
  2489. refresh going on, then the routine simply restarts the timer and
  2490. exits.
  2491. Arguments:
  2492. Return Value:
  2493. none
  2494. --*/
  2495. {
  2496. CTELockHandle OldIrq;
  2497. if (!pTimerQEntry)
  2498. {
  2499. NbtConfig.pRefreshTimer = NULL;
  2500. return;
  2501. }
  2502. CHECK_PTR(pTimerQEntry);
  2503. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2504. if (NodeType & BNODE)
  2505. {
  2506. pTimerQEntry->Flags = 0; // Do not restart the timer
  2507. NbtConfig.pRefreshTimer = NULL;
  2508. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2509. return;
  2510. }
  2511. if (!(NbtConfig.GlobalRefreshState & NBT_G_REFRESHING_NOW))
  2512. {
  2513. // this is a global flag that prevents a second refresh
  2514. // from starting when one is currently going on.
  2515. //
  2516. if (NT_SUCCESS(CTEQueueForNonDispProcessing (DelayedRefreshBegin,
  2517. NULL, NULL, NULL, NULL, TRUE)))
  2518. {
  2519. NbtConfig.GlobalRefreshState |= NBT_G_REFRESHING_NOW;
  2520. }
  2521. } // doing refresh now
  2522. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2523. // set any new timeout value and restart the timer
  2524. //
  2525. pTimerQEntry->DeltaTime = NbtConfig.MinimumTtl/NbtConfig.RefreshDivisor;
  2526. pTimerQEntry->Flags |= TIMER_RESTART;
  2527. }
  2528. //----------------------------------------------------------------------------
  2529. VOID
  2530. DelayedRefreshBegin(
  2531. IN tDGRAM_SEND_TRACKING *pUnused1,
  2532. IN PVOID pUnused2,
  2533. IN PVOID pUnused3,
  2534. IN tDEVICECONTEXT *pUnused4
  2535. )
  2536. /*++
  2537. Routine Description:
  2538. This routine handles starting up sending name refreshes to the name server.
  2539. The idea is to set the timeout to T/8 and check for names with the Refresh
  2540. bit cleared - re-registering those names. At T=4 and T=0, clear all bits
  2541. and refresh all names. The Inbound code sets the refresh bit when it gets a
  2542. refresh response from the NS.
  2543. Arguments:
  2544. Return Value:
  2545. none
  2546. --*/
  2547. {
  2548. CTELockHandle OldIrq;
  2549. tNAMEADDR *pNameAddr;
  2550. NTSTATUS status;
  2551. tHASHTABLE *pHashTable;
  2552. LONG i;
  2553. PLIST_ENTRY pHead;
  2554. PLIST_ENTRY pEntry;
  2555. tDEVICECONTEXT *pDeviceContext;
  2556. CTEULONGLONG Adapter;
  2557. BOOLEAN fTimeToSwitch = FALSE;
  2558. BOOLEAN fTimeToRefresh = FALSE;
  2559. USHORT TimeoutsBeforeSwitching;
  2560. ULONG TimeoutsBeforeNextRefresh;
  2561. CTESystemTime CurrentTime;
  2562. ULONG TimeoutDelta;
  2563. USHORT NumTimeoutIntervals;
  2564. //
  2565. // If the refresh timeout has been set to the maximum value then do
  2566. // not send any refreshes to the name server
  2567. //
  2568. if (NbtConfig.MinimumTtl == NBT_MAXIMUM_TTL)
  2569. {
  2570. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  2571. return;
  2572. }
  2573. LOCATION(0x12);
  2574. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2575. CTEQuerySystemTime (CurrentTime);
  2576. ExSystemTimeToLocalTime (&CurrentTime, &CurrentTime);
  2577. TimeoutDelta = NbtConfig.MinimumTtl/NbtConfig.RefreshDivisor;
  2578. NumTimeoutIntervals = (USHORT)
  2579. (((CurrentTime.QuadPart - NbtConfig.LastRefreshTime.QuadPart) + ((LONGLONG)TimeoutDelta*10000/2))
  2580. / ((LONGLONG)TimeoutDelta*10000)); // in 100 nano second units
  2581. NbtConfig.LastRefreshTime = CurrentTime;
  2582. //
  2583. // NumTimeoutIntervals > 1 if we were sleeping
  2584. //
  2585. if (NumTimeoutIntervals > 1)
  2586. {
  2587. //
  2588. // If we crossed Ttl/2 or Ttl while sleeping, refresh all names
  2589. //
  2590. TimeoutsBeforeNextRefresh = (NbtConfig.RefreshDivisor/2)
  2591. - (NbtConfig.sTimeoutCount % (NbtConfig.RefreshDivisor/2));
  2592. NbtConfig.sTimeoutCount += NumTimeoutIntervals; // Up the timeout count
  2593. //
  2594. // Refresh all of the names if
  2595. // a) we crossed Ttl/2 during sleep, or
  2596. // b) we are within Ttl/4 of the Ttl
  2597. //
  2598. if ((NumTimeoutIntervals > TimeoutsBeforeNextRefresh) ||
  2599. ((NbtConfig.RefreshDivisor-NbtConfig.sTimeoutCount) < (NbtConfig.RefreshDivisor/4)))
  2600. {
  2601. fTimeToRefresh = TRUE;
  2602. }
  2603. }
  2604. else
  2605. {
  2606. NbtConfig.sTimeoutCount++; // Up the timeout count for this cycle!
  2607. //
  2608. // If it has been over an hour (DEFAULT_SWITCH_TTL) since we last switched,
  2609. // then set fTimeToSwitch = TRUE
  2610. //
  2611. TimeoutsBeforeSwitching =(USHORT)((DEFAULT_SWITCH_TTL*NbtConfig.RefreshDivisor)/NbtConfig.MinimumTtl);
  2612. fTimeToSwitch = (NbtConfig.sTimeoutCount - NbtConfig.LastSwitchTimeoutCount)
  2613. >= TimeoutsBeforeSwitching;
  2614. fTimeToRefresh = (NbtConfig.sTimeoutCount >= (NbtConfig.RefreshDivisor/2));
  2615. if (fTimeToSwitch)
  2616. {
  2617. NbtConfig.LastSwitchTimeoutCount = NbtConfig.sTimeoutCount;
  2618. }
  2619. }
  2620. NbtConfig.sTimeoutCount %= NbtConfig.RefreshDivisor;
  2621. //
  2622. // Reset the clock if we are Refreshing everything
  2623. //
  2624. if (fTimeToRefresh)
  2625. {
  2626. NbtConfig.sTimeoutCount = 0;
  2627. fTimeToSwitch = FALSE;
  2628. }
  2629. //
  2630. // Set some special-case information
  2631. //
  2632. if (0 == NbtConfig.sTimeoutCount)
  2633. {
  2634. NbtConfig.LastSwitchTimeoutCount = 0;
  2635. }
  2636. IF_DBG(NBT_DEBUG_REFRESH)
  2637. KdPrint(("Nbt.DelayedRefreshBegin: fTimeToRefresh=<%d>,fTimeToSwitch=<%d>, MinTtl=<%d>, RefDiv=<%d>\n"
  2638. "TimeoutCount: %d, LastSwTimeoutCount: %d\n",
  2639. fTimeToRefresh, fTimeToSwitch, NbtConfig.MinimumTtl, NbtConfig.RefreshDivisor,
  2640. NbtConfig.sTimeoutCount, NbtConfig.LastSwitchTimeoutCount));
  2641. //
  2642. // go through the local table clearing the REFRESHED bit and sending
  2643. // name refreshes to the name server
  2644. //
  2645. pHashTable = NbtConfig.pLocalHashTbl;
  2646. if (fTimeToRefresh || fTimeToSwitch)
  2647. {
  2648. CTEULONGLONG ToRefreshMask = 0;
  2649. PLIST_ENTRY pHead1,pEntry1;
  2650. for (i=0 ;i < pHashTable->lNumBuckets ;i++ )
  2651. {
  2652. pHead = &pHashTable->Bucket[i];
  2653. pEntry = pHead->Flink;
  2654. //
  2655. // Go through each name in each bucket of the hashtable
  2656. //
  2657. while (pEntry != pHead)
  2658. {
  2659. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  2660. CHECK_PTR(pNameAddr);
  2661. // don't refresh scope names or names in conflict or that are the
  2662. // broadcast name "* ", or Quick added names.(since these are
  2663. // not registered on the network)
  2664. //
  2665. if (!(pNameAddr->NameTypeState & STATE_RESOLVED) ||
  2666. (pNameAddr->Name[0] == '*') ||
  2667. (IsBrowserName(pNameAddr->Name)) ||
  2668. (pNameAddr->NameTypeState & NAMETYPE_QUICK))
  2669. {
  2670. pEntry = pEntry->Flink;
  2671. continue;
  2672. }
  2673. if (fTimeToRefresh)
  2674. {
  2675. //
  2676. // Clear the refreshed bits so all names get refreshed if we are
  2677. // at interval 0 or interval NbtConfig.RefreshDivisor/2
  2678. //
  2679. pNameAddr->RefreshMask = 0;
  2680. }
  2681. //
  2682. // Set the ToRefreshMask to include any Devices not Refreshed previously
  2683. //
  2684. ToRefreshMask |= (pNameAddr->AdapterMask & ~pNameAddr->RefreshMask);
  2685. pEntry = pEntry->Flink; // next hash table entry
  2686. }
  2687. } // for ( .. pHashTable .. )
  2688. //
  2689. // Go through each adapter checking if a name needs to be Refreshed on this adapter.
  2690. //
  2691. pHead1 = &NbtConfig.DeviceContexts;
  2692. pEntry1 = pHead1->Flink;
  2693. while (pEntry1 != pHead1)
  2694. {
  2695. pDeviceContext = CONTAINING_RECORD(pEntry1,tDEVICECONTEXT,Linkage);
  2696. pEntry1 = pEntry1->Flink;
  2697. //
  2698. // If we are currently switched to the backup, then try
  2699. // to switch back to the primary
  2700. //
  2701. if (pDeviceContext->SwitchedToBackup)
  2702. {
  2703. SwitchToBackup(pDeviceContext);
  2704. pDeviceContext->RefreshToBackup = FALSE;
  2705. }
  2706. else if (fTimeToRefresh) // If this is a fresh Refresh cycle, restart from the primary
  2707. {
  2708. pDeviceContext->RefreshToBackup = FALSE;
  2709. }
  2710. else if ((pDeviceContext->AdapterMask & ToRefreshMask) && // do we need to switch on this device
  2711. (pDeviceContext->lBackupServer != LOOP_BACK))
  2712. {
  2713. pDeviceContext->RefreshToBackup = ~pDeviceContext->RefreshToBackup;
  2714. }
  2715. }
  2716. }
  2717. // always start at the first name in the hash table. As each name gets
  2718. // refreshed NextRefresh will be hit to get the next name etc..
  2719. //
  2720. NbtConfig.CurrentHashBucket = 0;
  2721. GetNextName(NULL,&pNameAddr); // get the next(first) name in the hash table
  2722. status = STATUS_UNSUCCESSFUL;
  2723. if (pNameAddr)
  2724. {
  2725. LOCATION(0x13);
  2726. status = StartRefresh(pNameAddr, NULL, &OldIrq, TRUE);
  2727. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2728. //
  2729. // If this routine fails then the address element increment done in
  2730. // GetNextName has to be undone here
  2731. //
  2732. if (!NT_SUCCESS(status))
  2733. {
  2734. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  2735. NBT_DEREFERENCE_ADDRESS (pNameAddr->pAddressEle, REF_ADDR_REFRESH);
  2736. }
  2737. }
  2738. else
  2739. {
  2740. NbtConfig.GlobalRefreshState &= ~NBT_G_REFRESHING_NOW;
  2741. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2742. }
  2743. }
  2744. //----------------------------------------------------------------------------
  2745. VOID
  2746. RemoteHashTimeout(
  2747. PVOID pContext,
  2748. PVOID pContext2,
  2749. tTIMERQENTRY *pTimerQEntry
  2750. )
  2751. /*++
  2752. Routine Description:
  2753. This routine handles deleting names in the Remote Hash table that are
  2754. old. The basic alorithm scans the table looking at the Timed_out bit.
  2755. If it is set then the name is deleted, otherwise the bit is set. This
  2756. means the names can live as long as 2*Timeout or as little as Timeout.
  2757. So set the Timeout to 6 Minutes and names live 9 minutes +- 3 minutes.
  2758. Arguments:
  2759. Return Value:
  2760. none
  2761. --*/
  2762. {
  2763. CTELockHandle OldIrq;
  2764. CTELockHandle OldIrq1;
  2765. tNAMEADDR *pNameAddr;
  2766. tHASHTABLE *pHashTable;
  2767. LONG i;
  2768. PLIST_ENTRY pHead;
  2769. PLIST_ENTRY pEntry;
  2770. PLIST_ENTRY pDeviceHead;
  2771. PLIST_ENTRY pDeviceEntry;
  2772. tDEVICECONTEXT *pDeviceContext;
  2773. tLOWERCONNECTION *pLowerConn;
  2774. ULONG TimeoutCount;
  2775. if (!pTimerQEntry)
  2776. {
  2777. //
  2778. // The Timer is being cancelled
  2779. //
  2780. NbtConfig.pRemoteHashTimer = NULL;
  2781. return;
  2782. }
  2783. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2784. //
  2785. // Update the Remote cache timestamp
  2786. //
  2787. NbtConfig.CacheTimeStamp++;
  2788. //
  2789. // go through the remote table deleting names that have timeout bits
  2790. // set and setting the bits for names that have the bit clear
  2791. //
  2792. pHashTable = NbtConfig.pRemoteHashTbl;
  2793. for (i=0;i < pHashTable->lNumBuckets ;i++ )
  2794. {
  2795. pHead = &pHashTable->Bucket[i];
  2796. pEntry = pHead->Flink;
  2797. while (pEntry != pHead)
  2798. {
  2799. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  2800. pEntry = pEntry->Flink;
  2801. //
  2802. // do not delete scope entries, and do not delete names that
  2803. // that are still resolving, and do not delete names that are
  2804. // being used by someone (refcount > 1)
  2805. //
  2806. if ((pNameAddr->NameTypeState & (STATE_RESOLVED | STATE_RELEASED)) &&
  2807. (pNameAddr->RefCount <= 1))
  2808. {
  2809. if ((pNameAddr->TimeOutCount == 0) ||
  2810. ((pContext == NbtConfig.pRemoteHashTbl) &&
  2811. !(pNameAddr->NameTypeState & NAMETYPE_SCOPE)))
  2812. {
  2813. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  2814. }
  2815. else if (!(pNameAddr->NameTypeState & NAMETYPE_SCOPE))
  2816. {
  2817. pNameAddr->TimeOutCount--;
  2818. }
  2819. }
  2820. }
  2821. }
  2822. // *** Inbound Connections Cleanup *** //
  2823. //
  2824. // Go through each Device and cleanup any lingering connections waiting in the Inbound state
  2825. // Start with the SmbDevice
  2826. //
  2827. pDeviceHead = pDeviceEntry = &NbtConfig.DeviceContexts;
  2828. if (pNbtSmbDevice)
  2829. {
  2830. pDeviceContext = pNbtSmbDevice;
  2831. }
  2832. else if ((pDeviceEntry = pDeviceEntry->Flink) != pDeviceHead)
  2833. {
  2834. pDeviceContext = CONTAINING_RECORD(pDeviceEntry,tDEVICECONTEXT,Linkage);
  2835. }
  2836. else
  2837. {
  2838. pDeviceContext = NULL;
  2839. }
  2840. while (pDeviceContext)
  2841. {
  2842. CTESpinLock(pDeviceContext,OldIrq1);
  2843. //
  2844. // Set the timeout based on the Resource usage!
  2845. //
  2846. if (pDeviceContext->NumWaitingForInbound > NbtConfig.MaxBackLog)
  2847. {
  2848. TimeoutCount = MIN_INBOUND_STATE_TIMEOUT / REMOTE_HASH_TIMEOUT; // Minimum Timeout value
  2849. }
  2850. else if (pDeviceContext->NumWaitingForInbound > NbtConfig.MaxBackLog/2)
  2851. {
  2852. TimeoutCount = MED_INBOUND_STATE_TIMEOUT / REMOTE_HASH_TIMEOUT; // Medium Timeout value
  2853. }
  2854. else
  2855. {
  2856. TimeoutCount = MAX_INBOUND_STATE_TIMEOUT / REMOTE_HASH_TIMEOUT; // Maximum Timeout Value
  2857. }
  2858. //
  2859. // Now go through the list of Inbound connections and see if
  2860. // we need to cleanup any that have lingering around for too long!
  2861. //
  2862. pHead = &pDeviceContext->WaitingForInbound;
  2863. pEntry = pHead->Flink;
  2864. while (pEntry != pHead)
  2865. {
  2866. pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
  2867. pEntry = pEntry->Flink;
  2868. pLowerConn->TimeUnitsInLastState++;
  2869. if (pLowerConn->TimeUnitsInLastState > TimeoutCount)
  2870. {
  2871. RemoveEntryList (&pLowerConn->Linkage);
  2872. InitializeListHead (&pLowerConn->Linkage);
  2873. SET_STATE_LOWER(pLowerConn, NBT_IDLE); // so that Inbound doesn't start processing it!
  2874. if (pLowerConn->SpecialAlloc)
  2875. {
  2876. InterlockedDecrement(&pLowerConn->pDeviceContext->NumSpecialLowerConn);
  2877. }
  2878. else
  2879. {
  2880. CTEQueueForNonDispProcessing (DelayedAllocLowerConn,
  2881. NULL,
  2882. NULL,
  2883. NULL,
  2884. pLowerConn->pDeviceContext,
  2885. TRUE);
  2886. }
  2887. ASSERT (pLowerConn->RefCount == 2);
  2888. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, TRUE); // RefCount: 2 -> 1
  2889. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CREATE, TRUE); // Close all the Tcp handles
  2890. InterlockedDecrement (&pDeviceContext->NumWaitingForInbound);
  2891. }
  2892. } // pDeviceContext->WaitingForInbound List
  2893. CTESpinFree(pDeviceContext,OldIrq1);
  2894. if ((pDeviceEntry = pDeviceEntry->Flink) != pDeviceHead)
  2895. {
  2896. pDeviceContext = CONTAINING_RECORD(pDeviceEntry,tDEVICECONTEXT,Linkage);
  2897. }
  2898. else
  2899. {
  2900. pDeviceContext = NULL;
  2901. }
  2902. } // NbtConfig.DeviceContexts List
  2903. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2904. // restart the timer
  2905. //
  2906. pTimerQEntry->Flags |= TIMER_RESTART;
  2907. return;
  2908. }
  2909. //----------------------------------------------------------------------------
  2910. VOID
  2911. NextKeepAlive(
  2912. IN tDGRAM_SEND_TRACKING *pTracker,
  2913. IN NTSTATUS status,
  2914. IN ULONG Info
  2915. )
  2916. /*++
  2917. Routine Description:
  2918. This routine handles sending subsequent KeepAlives for sessions.
  2919. This is the "Client Completion" routine of the TdiSend that sends the
  2920. keep alive on the session.
  2921. Arguments:
  2922. Return Value:
  2923. none
  2924. --*/
  2925. {
  2926. tLOWERCONNECTION *pLowerConnLast;
  2927. tLOWERCONNECTION *pLowerConn;
  2928. tDEVICECONTEXT *pDeviceContext;
  2929. PUSH_LOCATION(0x92);
  2930. pDeviceContext = pTracker->pDeviceContext;
  2931. pLowerConnLast = (tLOWERCONNECTION *)pTracker->pClientEle;
  2932. // get the next session to send a keep alive on, if there is one, otherwise
  2933. // free the session header block.
  2934. //
  2935. GetNextKeepAlive (pDeviceContext, &pDeviceContext, pLowerConnLast, &pLowerConn, pTracker);
  2936. NBT_DEREFERENCE_LOWERCONN (pLowerConnLast, REF_LOWC_KEEP_ALIVE, FALSE);
  2937. status = STATUS_UNSUCCESSFUL;
  2938. if (pLowerConn)
  2939. {
  2940. pTracker->pDeviceContext = pDeviceContext;
  2941. pTracker->pClientEle = (tCLIENTELE *)pLowerConn;
  2942. ASSERT((pTracker->SendBuffer.HdrLength + pTracker->SendBuffer.Length) == 4);
  2943. PUSH_LOCATION(0x91);
  2944. #ifndef VXD
  2945. // this may wind up the stack if the completion occurs synchronously,
  2946. // because the completion routine is this routine, so call a routine
  2947. // that sets up a dpc to to the send, which will not run until this
  2948. // procedure returns and we get out of raised irql.
  2949. //
  2950. status = NTSendSession (pTracker, pLowerConn, NextKeepAlive);
  2951. #else
  2952. (void) TcpSendSession (pTracker, pLowerConn, NextKeepAlive);
  2953. status = STATUS_SUCCESS;
  2954. #endif
  2955. }
  2956. if (!NT_SUCCESS(status))
  2957. {
  2958. if (pLowerConn)
  2959. {
  2960. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_KEEP_ALIVE, FALSE);
  2961. }
  2962. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  2963. }
  2964. }
  2965. //----------------------------------------------------------------------------
  2966. VOID
  2967. GetNextKeepAlive(
  2968. tDEVICECONTEXT *pDeviceContext,
  2969. tDEVICECONTEXT **ppDeviceContextOut,
  2970. tLOWERCONNECTION *pLowerConnIn,
  2971. tLOWERCONNECTION **ppLowerConnOut,
  2972. tDGRAM_SEND_TRACKING *pTracker
  2973. )
  2974. /*++
  2975. Routine Description:
  2976. This routine handles sending session keep Alives to the other end of a
  2977. connection about once a minute or so.
  2978. Arguments:
  2979. Return Value:
  2980. none
  2981. --*/
  2982. {
  2983. CTELockHandle OldIrq;
  2984. CTELockHandle OldIrq1;
  2985. CTELockHandle OldIrq2;
  2986. tLOWERCONNECTION *pLowerConn;
  2987. PLIST_ENTRY pHead;
  2988. PLIST_ENTRY pEntry;
  2989. PLIST_ENTRY pHeadDevice;
  2990. PLIST_ENTRY pEntryDevice;
  2991. NTSTATUS status;
  2992. tDEVICECONTEXT *pEntryDeviceContext;
  2993. *ppLowerConnOut = NULL;
  2994. //
  2995. // loop through all the adapter cards looking at all connections
  2996. //
  2997. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  2998. //
  2999. // Verify that the Device passed in is a valid device,
  3000. // otherwise either pick the next Device, or fail
  3001. //
  3002. status = STATUS_UNSUCCESSFUL;
  3003. pEntryDevice = pHeadDevice = &NbtConfig.DeviceContexts;
  3004. while ((pEntryDevice = pEntryDevice->Flink) != pHeadDevice)
  3005. {
  3006. pEntryDeviceContext = CONTAINING_RECORD(pEntryDevice,tDEVICECONTEXT,Linkage);
  3007. if ((pEntryDeviceContext == pDeviceContext) ||
  3008. (pEntryDeviceContext->AdapterNumber > pTracker->RCount))
  3009. {
  3010. if (pEntryDeviceContext != pDeviceContext)
  3011. {
  3012. pLowerConnIn = NULL;
  3013. }
  3014. pDeviceContext = pEntryDeviceContext;
  3015. status = STATUS_SUCCESS;
  3016. break;
  3017. }
  3018. }
  3019. if (!NT_SUCCESS(status))
  3020. {
  3021. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  3022. return;
  3023. }
  3024. pEntryDevice = &pDeviceContext->Linkage;
  3025. while (pEntryDevice != pHeadDevice)
  3026. {
  3027. pDeviceContext = CONTAINING_RECORD(pEntryDevice,tDEVICECONTEXT,Linkage);
  3028. pEntryDevice = pEntryDevice->Flink;
  3029. // grab the device context spin lock so that the lower connection
  3030. // element does not get removed from the Q while we are checking the
  3031. // connection state
  3032. //
  3033. CTESpinLock(pDeviceContext,OldIrq);
  3034. pHead = &pDeviceContext->LowerConnection;
  3035. //
  3036. // get the next lower connection after this one one the list, but
  3037. // be sure this connection is still on the active list by checking
  3038. // the state.
  3039. //
  3040. // If this connection has been cleaned up in OutOfRsrcKill, then dont trust the linkages.
  3041. //
  3042. if (pLowerConnIn &&
  3043. !pLowerConnIn->OutOfRsrcFlag &&
  3044. ((pLowerConnIn->State == NBT_SESSION_UP) ||
  3045. (pLowerConnIn->State == NBT_SESSION_INBOUND)))
  3046. {
  3047. pEntry = pLowerConnIn->Linkage.Flink;
  3048. pLowerConnIn = NULL;
  3049. }
  3050. else
  3051. {
  3052. pEntry = pHead->Flink;
  3053. }
  3054. while (pEntry != pHead)
  3055. {
  3056. pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
  3057. //
  3058. // Inbound connections can hang around forever in that state if
  3059. // the session setup message never gets sent, so send keep
  3060. // alives on those too.
  3061. //
  3062. if ((pLowerConn->State == NBT_SESSION_UP) ||
  3063. (pLowerConn->State == NBT_SESSION_INBOUND))
  3064. {
  3065. // grab the spin lock, recheck the state and
  3066. // increment the reference count so that this connection cannot
  3067. // disappear while the keep alive is being sent and mess up
  3068. // the linked list.
  3069. CTESpinLock(pLowerConn,OldIrq2);
  3070. if ((pLowerConn->State != NBT_SESSION_UP ) &&
  3071. (pLowerConn->State != NBT_SESSION_INBOUND))
  3072. {
  3073. // this connection is probably back on the free connection
  3074. // list, so we will never satisfy the pEntry = pHead and
  3075. // loop forever, so just get out and send keepalives on the
  3076. // next timeout
  3077. //
  3078. pEntry = pEntry->Flink;
  3079. PUSH_LOCATION(0x91);
  3080. CTESpinFree(pLowerConn,OldIrq2);
  3081. break;
  3082. }
  3083. else if (pLowerConn->RefCount >= 3 )
  3084. {
  3085. //
  3086. // already a keep alive on this connection, or we
  3087. // are currently in the receive handler and do not
  3088. // need to send a keep alive.
  3089. //
  3090. pEntry = pEntry->Flink;
  3091. PUSH_LOCATION(0x93);
  3092. CTESpinFree(pLowerConn,OldIrq2);
  3093. continue;
  3094. }
  3095. //
  3096. // found a connection to send a keep alive on
  3097. //
  3098. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_KEEP_ALIVE);
  3099. //
  3100. // return the current position in the list of connections
  3101. //
  3102. pTracker->RCount = pDeviceContext->AdapterNumber;
  3103. *ppLowerConnOut = pLowerConn;
  3104. *ppDeviceContextOut = pDeviceContext;
  3105. CTESpinFree(pLowerConn,OldIrq2);
  3106. CTESpinFree(pDeviceContext,OldIrq);
  3107. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  3108. return;
  3109. }
  3110. pEntry = pEntry->Flink;
  3111. }
  3112. CTESpinFree(pDeviceContext,OldIrq);
  3113. }
  3114. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  3115. return;
  3116. }
  3117. //----------------------------------------------------------------------------
  3118. VOID
  3119. SessionKeepAliveTimeout(
  3120. PVOID pContext,
  3121. PVOID pContext2,
  3122. tTIMERQENTRY *pTimerQEntry
  3123. )
  3124. /*++
  3125. Routine Description:
  3126. This routine handles starting the non dispatch level routine to send
  3127. keep alives.
  3128. Arguments:
  3129. Return Value:
  3130. none
  3131. --*/
  3132. {
  3133. if (!pTimerQEntry)
  3134. {
  3135. NbtConfig.pSessionKeepAliveTimer = NULL;
  3136. return;
  3137. }
  3138. CHECK_PTR(pTimerQEntry);
  3139. if (!NT_SUCCESS(CTEQueueForNonDispProcessing (DelayedSessionKeepAlive,
  3140. NULL, NULL, NULL, NULL, FALSE)))
  3141. {
  3142. IF_DBG(NBT_DEBUG_REFRESH)
  3143. KdPrint (("Nbt.SessionKeepAliveTimeout: Failed to Queue DelayedSessionKeepAlive!!!\n"));
  3144. }
  3145. // restart the timer
  3146. //
  3147. pTimerQEntry->Flags |= TIMER_RESTART;
  3148. return;
  3149. }
  3150. //----------------------------------------------------------------------------
  3151. VOID
  3152. DelayedSessionKeepAlive(
  3153. IN tDGRAM_SEND_TRACKING *Unused1,
  3154. IN PVOID Unused2,
  3155. IN PVOID Unused3,
  3156. IN tDEVICECONTEXT *pUnused4
  3157. )
  3158. /*++
  3159. Routine Description:
  3160. This routine handles sending session keep Alives to the other end of a
  3161. connection about once a minute or so.
  3162. Arguments:
  3163. Return Value:
  3164. none
  3165. --*/
  3166. {
  3167. NTSTATUS status;
  3168. tLOWERCONNECTION *pLowerConn;
  3169. tDEVICECONTEXT *pDeviceContext;
  3170. tSESSIONHDR *pSessionHdr;
  3171. tDGRAM_SEND_TRACKING *pTracker;
  3172. CTEPagedCode();
  3173. if (!(pSessionHdr = (tSESSIONHDR *)NbtAllocMem(sizeof(tSESSIONERROR),NBT_TAG('S'))))
  3174. {
  3175. return;
  3176. }
  3177. // get a tracker structure, which has a SendInfo structure in it
  3178. if (!NT_SUCCESS(status = GetTracker(&pTracker, NBT_TRACKER_KEEP_ALIVE)))
  3179. {
  3180. CTEMemFree((PVOID)pSessionHdr);
  3181. return;
  3182. }
  3183. //
  3184. // go through the list of connections attached to each adapter and
  3185. // send a session keep alive pdu on each
  3186. //
  3187. pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink,
  3188. tDEVICECONTEXT,Linkage);
  3189. // get the next session to send a keep alive on, if there is one, otherwise
  3190. // free the session header block.
  3191. //
  3192. pTracker->RCount = 0; // This field keeps track of the last device
  3193. GetNextKeepAlive(pDeviceContext, &pDeviceContext, NULL, &pLowerConn, pTracker);
  3194. if (pLowerConn)
  3195. {
  3196. // if we have found a connection, send the first keep alive. Subsequent
  3197. // keep alives will be sent by the completion routine, NextKeepAlive()
  3198. //
  3199. CHECK_PTR(pTracker);
  3200. pTracker->SendBuffer.pDgramHdr = (PVOID)pSessionHdr;
  3201. pTracker->SendBuffer.HdrLength = sizeof(tSESSIONHDR);
  3202. pTracker->SendBuffer.Length = 0;
  3203. pTracker->SendBuffer.pBuffer = NULL;
  3204. pSessionHdr->Flags = NBT_SESSION_FLAGS; // always zero
  3205. pTracker->pDeviceContext = pDeviceContext;
  3206. pTracker->pClientEle = (tCLIENTELE *)pLowerConn;
  3207. CHECK_PTR(pSessionHdr);
  3208. pSessionHdr->Type = NBT_SESSION_KEEP_ALIVE; // 85
  3209. pSessionHdr->Length = 0; // no data following the length byte
  3210. status = TcpSendSession(pTracker, pLowerConn, NextKeepAlive);
  3211. }
  3212. else
  3213. {
  3214. CTEMemFree((PVOID)pSessionHdr);
  3215. FreeTracker (pTracker, RELINK_TRACKER);
  3216. }
  3217. }
  3218. //----------------------------------------------------------------------------
  3219. VOID
  3220. IncrementNameStats(
  3221. IN ULONG StatType,
  3222. IN BOOLEAN IsNameServer
  3223. )
  3224. /*++
  3225. Routine Description:
  3226. This routine increments statistics on names that resolve either through
  3227. the WINS or through broadcast.
  3228. Arguments:
  3229. Return Value:
  3230. none
  3231. --*/
  3232. {
  3233. //
  3234. // Increment the stattype if the name server is true, that way we can
  3235. // differentiate queries and registrations to the name server or not.
  3236. //
  3237. if (IsNameServer)
  3238. {
  3239. StatType += 2;
  3240. }
  3241. NameStatsInfo.Stats[StatType]++;
  3242. }
  3243. //----------------------------------------------------------------------------
  3244. VOID
  3245. SaveBcastNameResolved(
  3246. IN PUCHAR pName
  3247. )
  3248. /*++
  3249. Routine Description:
  3250. This routine saves the name in LIFO list, so we can see the last
  3251. N names that resolved via broadcast.
  3252. Arguments:
  3253. Return Value:
  3254. none
  3255. --*/
  3256. {
  3257. ULONG Index;
  3258. Index = NameStatsInfo.Index;
  3259. CTEMemCopy(&NameStatsInfo.NamesReslvdByBcast[Index],
  3260. pName,
  3261. NETBIOS_NAME_SIZE);
  3262. NameStatsInfo.Index++;
  3263. if (NameStatsInfo.Index >= SIZE_RESOLVD_BY_BCAST_CACHE)
  3264. {
  3265. NameStatsInfo.Index = 0;
  3266. }
  3267. }
  3268. //
  3269. // These are names that should never be sent to WINS.
  3270. //
  3271. BOOL
  3272. IsBrowserName(
  3273. IN PCHAR pName
  3274. )
  3275. {
  3276. CHAR cNameType = pName[NETBIOS_NAME_SIZE - 1];
  3277. return (
  3278. (cNameType == 0x1E)
  3279. || (cNameType == 0x1D)
  3280. || (cNameType == 0x01)
  3281. );
  3282. }
  3283. //
  3284. // Returns the node type that should be used with a request,
  3285. // based on NetBIOS name type. This is intended to help the
  3286. // node to behave like a BNODE for browser names only.
  3287. //
  3288. AppropriateNodeType(
  3289. IN PCHAR pName,
  3290. IN ULONG NodeType
  3291. )
  3292. {
  3293. ULONG LocalNodeType = NodeType;
  3294. if (LocalNodeType & BNODE)
  3295. {
  3296. if ( IsBrowserName ( pName ) )
  3297. {
  3298. LocalNodeType &= BNODE;
  3299. }
  3300. }
  3301. return LocalNodeType;
  3302. }