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

4549 lines
160 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Inbound.c
  5. Abstract:
  6. This file implements the inbound name service pdu handling. It handles
  7. name queries from the network and Registration responses from the network.
  8. Author:
  9. Jim Stewart (Jimst) 10-2-92
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "ctemacro.h"
  14. #include "inbound.tmh"
  15. NTSTATUS
  16. DecodeNodeStatusResponse(
  17. IN tNAMEHDR UNALIGNED *pNameHdr,
  18. IN ULONG Length,
  19. IN PUCHAR pName,
  20. IN ULONG lNameSize,
  21. IN tIPADDRESS SrcIpAddress
  22. );
  23. NTSTATUS
  24. SendNodeStatusResponse(
  25. IN tNAMEHDR UNALIGNED *pInNameHdr,
  26. IN ULONG Length,
  27. IN PUCHAR pName,
  28. IN ULONG lNameSize,
  29. IN tIPADDRESS SrcIpAddress,
  30. IN USHORT SrcPort,
  31. IN tDEVICECONTEXT *pDeviceContext
  32. );
  33. NTSTATUS
  34. UpdateNameState(
  35. IN tADDSTRUCT UNALIGNED *pAddrStruct,
  36. IN tNAMEADDR *pNameAddr,
  37. IN ULONG Length,
  38. #ifdef MULTIPLE_WINS
  39. IN PULONG pContextFlags,
  40. #endif
  41. IN tDEVICECONTEXT *pDeviceContext,
  42. IN BOOLEAN SrcIsNameServer,
  43. IN tDGRAM_SEND_TRACKING *Context,
  44. IN CTELockHandle OldIrq1
  45. );
  46. NTSTATUS
  47. ChkIfValidRsp(
  48. IN tNAMEHDR UNALIGNED *pNameHdr,
  49. IN LONG lNumBytes,
  50. IN tNAMEADDR *pNameAddr
  51. );
  52. NTSTATUS
  53. ChooseBestIpAddress(
  54. IN tADDSTRUCT UNALIGNED *pAddrStruct,
  55. IN ULONG Len,
  56. IN tDEVICECONTEXT *pDeviceContext,
  57. OUT tDGRAM_SEND_TRACKING *pTracker,
  58. OUT tIPADDRESS *pIpAddress,
  59. IN BOOLEAN fReturnAddrList
  60. );
  61. NTSTATUS
  62. GetNbFlags(
  63. IN tNAMEHDR UNALIGNED *pNameHdr,
  64. IN LONG lNameSize,
  65. IN LONG lNumBytes,
  66. OUT USHORT *pRegType
  67. );
  68. VOID
  69. PrintHexString(
  70. IN tNAMEHDR UNALIGNED *pNameHdr,
  71. IN ULONG lNumBytes
  72. );
  73. ULONG
  74. MakeList(
  75. IN tDEVICECONTEXT *pDeviceContext,
  76. IN ULONG CountAddrs,
  77. IN tADDSTRUCT UNALIGNED *pAddrStruct,
  78. IN tIPADDRESS *pAddrArray,
  79. IN ULONG SizeOfAddrArray,
  80. IN BOOLEAN IsSubnetMatch
  81. );
  82. BOOL
  83. IsBrowserName(
  84. IN PCHAR pName
  85. );
  86. #if DBG
  87. #define KdPrintHexString(pHdr,NumBytes) \
  88. PrintHexString(pHdr,NumBytes)
  89. #else
  90. #define KdPrintHexString(pHdr,NumBytes)
  91. #endif
  92. //----------------------------------------------------------------------------
  93. BOOLEAN
  94. IsRemoteAddress(
  95. IN tNAMEADDR *pNameAddr,
  96. IN tIPADDRESS IpAddress
  97. )
  98. {
  99. ULONG i;
  100. for (i=0; i<pNameAddr->RemoteCacheLen; i++)
  101. {
  102. if (pNameAddr->pRemoteIpAddrs[i].IpAddress == IpAddress)
  103. {
  104. return TRUE;
  105. }
  106. }
  107. return FALSE;
  108. }
  109. //----------------------------------------------------------------------------
  110. NTSTATUS
  111. QueryFromNet(
  112. IN tDEVICECONTEXT *pDeviceContext,
  113. IN PVOID pSrcAddress,
  114. IN tNAMEHDR UNALIGNED *pNameHdr,
  115. IN LONG lNumBytes,
  116. IN USHORT OpCodeFlags,
  117. IN BOOLEAN fBroadcast
  118. )
  119. /*++
  120. Routine Description:
  121. This routine handles both name query requests and responses. For Queries
  122. it checks if the name is registered on this node. If this node is a proxy
  123. it then forwards a name query onto the Name Server, adding the name to the
  124. remote proxy cache...
  125. Arguments:
  126. Return Value:
  127. NTSTATUS - success or not - failure means no response to net
  128. --*/
  129. {
  130. NTSTATUS status;
  131. LONG lNameSize;
  132. CHAR pName[NETBIOS_NAME_SIZE];
  133. PUCHAR pScope;
  134. tNAMEADDR *pNameAddr;
  135. tTIMERQENTRY *pTimer;
  136. COMPLETIONCLIENT pClientCompletion;
  137. #ifdef MULTIPLE_WINS
  138. tDGRAM_SEND_TRACKING *Context;
  139. ULONG AddrStructLength;
  140. USHORT RdLength; // The length field in the packet
  141. #else
  142. PVOID Context;
  143. #endif
  144. PTRANSPORT_ADDRESS pSourceAddress;
  145. tIPADDRESS SrcAddress;
  146. CTELockHandle OldIrq1;
  147. tQUERYRESP UNALIGNED *pQuery;
  148. USHORT SrcPort;
  149. tIPADDRESS IpAddr;
  150. tADDSTRUCT UNALIGNED *pAddrs;
  151. tIPADDRESS *pFailedAddresses;
  152. ULONG i, j, CountAddrs, InterfaceContext;
  153. tQUERY_ADDRS *pQueryAddrs = NULL;
  154. LONG MinimumBytes;
  155. pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
  156. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  157. SrcPort = ntohs(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port);
  158. #ifdef VXD
  159. //
  160. // is this a response from a DNS server? if yes then handle it
  161. // appropriately
  162. //
  163. if (SrcPort == NBT_DNSSERVER_UDP_PORT)
  164. {
  165. USHORT TransactionId;
  166. TransactionId = ntohs(pNameHdr->TransactId);
  167. if ( TransactionId >= DIRECT_DNS_NAME_QUERY_BASE )
  168. {
  169. ProcessDnsResponseDirect( pDeviceContext,
  170. pSrcAddress,
  171. pNameHdr,
  172. lNumBytes,
  173. OpCodeFlags );
  174. }
  175. else
  176. {
  177. ProcessDnsResponse( pDeviceContext,
  178. pSrcAddress,
  179. pNameHdr,
  180. lNumBytes,
  181. OpCodeFlags );
  182. }
  183. return(STATUS_DATA_NOT_ACCEPTED);
  184. }
  185. #endif
  186. //
  187. // check the pdu size for errors - be sure the name is long enough for
  188. // the scope on this machine.
  189. //
  190. if (lNumBytes < (NBT_MINIMUM_QUERY + NbtConfig.ScopeLength - 1))
  191. {
  192. IF_DBG(NBT_DEBUG_NAMESRV)
  193. KdPrint(("Nbt:Name Query PDU TOO short = %X,Src= %X\n",lNumBytes,SrcAddress));
  194. return(STATUS_DATA_NOT_ACCEPTED);
  195. }
  196. // get the name out of the network pdu and pass to routine to check
  197. // local table *TODO* this assumes just one name in the Query response...
  198. status = ConvertToAscii ((PCHAR) &pNameHdr->NameRR,
  199. (lNumBytes-1) - FIELD_OFFSET(tNAMEHDR,NameRR), // -1 for QUEST_STATUS
  200. pName,
  201. &pScope,
  202. &lNameSize);
  203. if (!NT_SUCCESS(status))
  204. {
  205. // IF_DBG(NBT_DEBUG_NAMESRV)
  206. KdPrint (("Nbt.QueryFromNet: WARNING!!! Rejecting Request -- ConvertToAscii FAILed\n"));
  207. return(STATUS_DATA_NOT_ACCEPTED);
  208. }
  209. // check if this is a request or a response pdu
  210. //
  211. // *** RESPONSE ***
  212. //
  213. if (OpCodeFlags & OP_RESPONSE)
  214. {
  215. if (!(OpCodeFlags & FL_AUTHORITY))
  216. {
  217. // *** Redirect Response from Wins ***
  218. //
  219. // This is a redirect response telling us to go to another
  220. // name server, which we do not support, so just return
  221. // *TODO*
  222. //
  223. return(STATUS_DATA_NOT_ACCEPTED);
  224. }
  225. //
  226. // check if this is a node status request, since is looks very similar
  227. // to a name query, except that the NBSTAT field is 0x21 instead of
  228. // 0x20
  229. //
  230. pQuery = (tQUERYRESP *) &pNameHdr->NameRR.NetBiosName[lNameSize];
  231. if ( ((PUCHAR)pQuery)[1] == QUEST_STATUS )
  232. {
  233. //
  234. // *** This is an AdapterStatus response! ***
  235. //
  236. tNODESTATUS *pNodeStatus = (tNODESTATUS *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  237. //
  238. // Bug# 125627
  239. // Check for valid Pdu data + Size
  240. // The PDU is of the form:
  241. // tNAMEHDR --> TransactionId ==> Offset=0, Length=2 bytes
  242. // :
  243. // --> NameRR.NetbiosName ==> Offset=13, Length = lNameSize
  244. // --> NodeStatusResponse ==> Offset=13+lNameSize, Length >=11
  245. // --> NodeName[i] ==> Offset=13+lNameSize+11+(i*NBT_NODE_NAME_SIZE)
  246. //
  247. MinimumBytes = FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize + 11;
  248. if ((lNumBytes < MinimumBytes) || // so that we can read in "pNodeStatus->NumNames"
  249. (lNumBytes < (MinimumBytes + pNodeStatus->NumNames*NBT_NODE_NAME_SIZE)))
  250. {
  251. IF_DBG(NBT_DEBUG_NAMESRV)
  252. KdPrint (("Nbt.QueryFromNet: WARNING Bad AdapterStatusResp size -- lNumBytes=<%d> < <%d>\n",
  253. lNumBytes, (MinimumBytes + pNodeStatus->NumNames*NBT_NODE_NAME_SIZE)));
  254. ASSERT(0);
  255. return(STATUS_DATA_NOT_ACCEPTED);
  256. }
  257. status = DecodeNodeStatusResponse(pNameHdr, lNumBytes, pName, lNameSize, SrcAddress);
  258. return(STATUS_DATA_NOT_ACCEPTED);
  259. }
  260. //
  261. // *** We are processing a Name Query response! ***
  262. //
  263. //
  264. // check the Query response pdu size before dereferencing it!
  265. // The PDU is of the form:
  266. // tNAMEHDR --> TransactionId ==> Offset=0, Length=2 bytes
  267. // :
  268. // --> NameRR.NetbiosName ==> Offset=13, Length = lNameSize
  269. // --> QueryResponse ==> Offset=13+lNameSize, Length >=10
  270. //
  271. //
  272. if (IS_POS_RESPONSE(OpCodeFlags))
  273. {
  274. MinimumBytes = 13 + lNameSize + 16;
  275. }
  276. else
  277. {
  278. MinimumBytes = 13 + lNameSize + 10; // Upto Length field only
  279. }
  280. if (lNumBytes < MinimumBytes)
  281. {
  282. KdPrint (("Nbt.QueryFromNet: WARNING -- Bad QueryResp size, lNumBytes=<%d>, lNameSize=<%d>\n",
  283. lNumBytes, lNameSize));
  284. return(STATUS_DATA_NOT_ACCEPTED);
  285. }
  286. pAddrs = (tADDSTRUCT *) &pQuery->Flags;
  287. RdLength = ntohs(pQuery->Length);
  288. AddrStructLength = lNumBytes - (ULONG)((ULONG_PTR)&pQuery->Flags - (ULONG_PTR)pNameHdr);
  289. if (RdLength < AddrStructLength) {
  290. AddrStructLength = RdLength;
  291. }
  292. CountAddrs = AddrStructLength / tADDSTRUCT_SIZE;
  293. //
  294. // Call into IP to determine the outgoing interface for each address returned
  295. //
  296. if ((NbtConfig.ConnectOnRequestedInterfaceOnly) &&
  297. (!(ntohs(pAddrs[0].NbFlags) & FL_GROUP)) &&
  298. (CountAddrs && ((CountAddrs*tADDSTRUCT_SIZE) == AddrStructLength)) &&
  299. (pQueryAddrs = (tQUERY_ADDRS *) NbtAllocMem(CountAddrs*sizeof(tQUERY_ADDRS),NBT_TAG2('13'))))
  300. {
  301. CTEZeroMemory(pQueryAddrs, CountAddrs*sizeof(tQUERY_ADDRS));
  302. for (i = 0; i < CountAddrs; i++)
  303. {
  304. pQueryAddrs[i].IpAddress = pAddrs[i].IpAddr;
  305. pDeviceContext->pFastQuery(pAddrs[i].IpAddr,&pQueryAddrs[i].Interface,&pQueryAddrs[i].Metric);
  306. }
  307. }
  308. //
  309. // call this routine to find the name, since it does not interpret the
  310. // state of the name as does FindName()
  311. //
  312. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  313. status = FindOnPendingList(pName,pNameHdr,FALSE,NETBIOS_NAME_SIZE,&pNameAddr);
  314. if (NT_SUCCESS(status))
  315. {
  316. pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  317. // remove any timer block and call the completion routine
  318. if ((pTimer = pNameAddr->pTimer))
  319. {
  320. ULONG Flags;
  321. tDGRAM_SEND_TRACKING *pTracker;
  322. tDEVICECONTEXT *pDevContext;
  323. USHORT NSOthersIndex, NSOthersLeft;
  324. ULONG ContextFlags;
  325. pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
  326. Flags = pTracker->Flags;
  327. //
  328. // Since this Wins server was able to respond, set the last responsive
  329. // pointer
  330. //
  331. if ((SrcIsNameServer(SrcAddress,SrcPort)) &&
  332. (pTracker->Flags & NBT_NAME_SERVER_OTHERS))
  333. {
  334. pTracker->pDeviceContext->lLastResponsive = pTracker->NSOthersIndex;
  335. }
  336. //
  337. // If this is not a response to a request sent by the PROXY code
  338. // and
  339. // MSNode && Error Response code && Src is NameServer && Currently
  340. // resolving with the name server, then switch to broadcast
  341. // ... or if it is a Pnode or Mnode and EnableLmHost or
  342. // ResolveWithDns is on, then
  343. // let the timer expire again, and try Lmhost.
  344. //
  345. if (
  346. #ifdef PROXY_NODE
  347. pNameAddr->ProxyReqType == NAMEREQ_REGULAR &&
  348. #endif
  349. (IS_NEG_RESPONSE(OpCodeFlags)))
  350. {
  351. if ((NodeType & (PNODE | MNODE | MSNODE)) &&
  352. (Flags & (NBT_NAME_SERVER | NBT_NAME_SERVER_BACKUP)))
  353. {
  354. // this should let MsnodeCompletion try the
  355. // backup WINS or broadcast processing next
  356. //
  357. pTracker->Flags |= WINS_NEG_RESPONSE;
  358. ExpireTimer (pTimer, &OldIrq1);
  359. }
  360. else
  361. {
  362. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  363. }
  364. if (pQueryAddrs)
  365. {
  366. CTEFreeMem (pQueryAddrs);
  367. }
  368. return(STATUS_DATA_NOT_ACCEPTED);
  369. }
  370. //
  371. // Check if any of the addresses that came over the net
  372. // belong to the set of failed addresses that we are tracking
  373. //
  374. if (pNameAddr->pTracker) // pTracker will be NULL for Proxy requests
  375. {
  376. if (pQueryAddrs)
  377. {
  378. //
  379. // Go through the list of addresses to see which ones can be
  380. // reached through this Device
  381. //
  382. InterfaceContext = pNameAddr->pTracker->pDeviceContext->IPInterfaceContext;
  383. for (i=0; i<CountAddrs; i++)
  384. {
  385. if (pQueryAddrs[i].Interface != InterfaceContext)
  386. {
  387. CountAddrs--;
  388. if (CountAddrs)
  389. {
  390. pQueryAddrs[i].Interface = pQueryAddrs[CountAddrs].Interface;
  391. pAddrs[i] = pAddrs[CountAddrs]; // Copy the last entry
  392. }
  393. pAddrs[CountAddrs].IpAddr = 0; // Set the last address entry to 0
  394. i--;
  395. }
  396. }
  397. CTEFreeMem (pQueryAddrs);
  398. pQueryAddrs = NULL;
  399. }
  400. AddrStructLength = CountAddrs * tADDSTRUCT_SIZE;
  401. //
  402. // We have now removed all the irrelevant entries
  403. // See if we also need to filter out any bad (known) addresses
  404. //
  405. if ((pNameAddr->pTracker->pFailedIpAddresses) && (pTimer->ClientCompletion))
  406. {
  407. pFailedAddresses = pNameAddr->pTracker->pFailedIpAddresses;
  408. if ((CountAddrs*tADDSTRUCT_SIZE) == AddrStructLength)
  409. {
  410. //
  411. // If some of these addresses had failed earlier, they should be purged
  412. //
  413. i = 0;
  414. while ((i < MAX_FAILED_IP_ADDRESSES) && (pFailedAddresses[i]))
  415. {
  416. for (j = 0; j < CountAddrs; j++)
  417. {
  418. if (pFailedAddresses[i] == (ULONG) ntohl(pAddrs[j].IpAddr))
  419. {
  420. pAddrs[j] = pAddrs[CountAddrs-1]; // Copy the last entry
  421. pAddrs[CountAddrs-1].IpAddr = 0; // Set the last entry to 0
  422. CountAddrs--;
  423. j--; // Now, read this new IP address
  424. }
  425. }
  426. i++;
  427. }
  428. }
  429. }
  430. if (0 == (AddrStructLength = CountAddrs*tADDSTRUCT_SIZE))
  431. {
  432. //
  433. // No new addresses were found -- consider this a negative response
  434. //
  435. if ((NodeType & (PNODE | MNODE | MSNODE)) &&
  436. (pTracker->Flags & (NBT_NAME_SERVER | NBT_NAME_SERVER_BACKUP)))
  437. {
  438. // this should let MsnodeCompletion try the
  439. // backup WINS or broadcast
  440. // processing when the timer times out.
  441. //
  442. pTracker->Flags |= WINS_NEG_RESPONSE;
  443. ExpireTimer (pTimer, &OldIrq1);
  444. }
  445. else
  446. {
  447. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  448. }
  449. return(STATUS_DATA_NOT_ACCEPTED);
  450. }
  451. //
  452. // save the Tracker's essential info since the call to StopTimer could
  453. // free pTracker
  454. //
  455. pNameAddr->pTracker->ResolutionContextFlags = pTracker->Flags;
  456. pNameAddr->pTracker->NSOthersIndex = pTracker->NSOthersIndex;
  457. pNameAddr->pTracker->NSOthersLeft = pTracker->NSOthersLeft;
  458. }
  459. else if (pQueryAddrs)
  460. {
  461. CTEFreeMem (pQueryAddrs);
  462. pQueryAddrs = NULL;
  463. }
  464. CHECK_PTR(pNameAddr);
  465. pDevContext = pTracker->pDeviceContext;
  466. //
  467. // this routine puts the timer block back on the timer Q, and
  468. // handles race conditions to cancel the timer when the timer
  469. // is expiring.
  470. //
  471. pNameAddr->pTimer = NULL;
  472. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE); // Since StopTimer can Deref name!
  473. status = StopTimer(pTimer,&pClientCompletion,&Context);
  474. LOCATION(0x42);
  475. //
  476. // we need to synchronize removing the name from the list
  477. // with MsNodeCompletion
  478. //
  479. if (pClientCompletion)
  480. {
  481. LOCATION(0x41);
  482. //
  483. // Remove from the pending list
  484. RemoveEntryList(&pNameAddr->Linkage);
  485. InitializeListHead(&pNameAddr->Linkage);
  486. // check the name query response ret code to see if the name
  487. // query succeeded or not.
  488. if (IS_POS_RESPONSE(OpCodeFlags))
  489. {
  490. BOOLEAN ResolvedByWins;
  491. LOCATION(0x40);
  492. //
  493. // Keep track of how many names are resolved by WINS and
  494. // keep a list of names not resolved by WINS
  495. //
  496. if (!(ResolvedByWins = SrcIsNameServer(SrcAddress,SrcPort)))
  497. {
  498. SaveBcastNameResolved(pName);
  499. }
  500. IncrementNameStats(NAME_QUERY_SUCCESS, ResolvedByWins);
  501. #ifdef PROXY_NODE
  502. // Set flag if the node queries is a PNODE
  503. //
  504. IF_PROXY(NodeType)
  505. {
  506. pNameAddr->fPnode = (pNameHdr->NameRR.NetBiosName[lNameSize+QUERY_NBFLAGS_OFFSET]
  507. & NODE_TYPE_MASK) == PNODE_VAL_IN_PKT;
  508. IF_DBG(NBT_DEBUG_PROXY)
  509. KdPrint(("QueryFromNet: POSITIVE RESPONSE to name query - %16.16s(%X)\n",
  510. pNameAddr->Name, pNameAddr->Name[15]));
  511. }
  512. #endif
  513. pNameAddr->AdapterMask |= pDevContext->AdapterMask;
  514. IpAddr = ((tADDSTRUCT UNALIGNED *)&pQuery->Flags)->IpAddr;
  515. status = UpdateNameState((tADDSTRUCT *)&pQuery->Flags,
  516. pNameAddr,
  517. AddrStructLength,
  518. &ContextFlags,
  519. pDevContext,
  520. SrcIsNameServer(SrcAddress,SrcPort),
  521. (tDGRAM_SEND_TRACKING *)Context,
  522. OldIrq1);
  523. //
  524. // since pNameAddr can be freed in UpdateNameState do not
  525. // access it here
  526. //
  527. pNameAddr = NULL;
  528. // status = STATUS_SUCCESS;
  529. }
  530. else // negative query response received
  531. {
  532. LOCATION(0x3f);
  533. //
  534. // Release the name. It will get dereferenced by the
  535. // cache timeout function (RemoteHashTimeout).
  536. //
  537. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  538. pNameAddr->NameTypeState |= STATE_RELEASED;
  539. //
  540. // the proxy maintains a negative cache of names that
  541. // do not exist in WINS. These are timed out by
  542. // the remote hash timer just as the resolved names
  543. // are timed out.
  544. //
  545. if (!(NodeType & PROXY))
  546. {
  547. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  548. }
  549. else if (pNameAddr->ProxyReqType != NAMEREQ_PROXY_REGISTRATION)
  550. {
  551. //
  552. // Add to cache as negative name entry
  553. //
  554. AddToHashTable (NbtConfig.pRemoteHashTbl,
  555. pNameAddr->Name,
  556. NbtConfig.pScope,
  557. pNameAddr->IpAddress,
  558. 0,
  559. pNameAddr,
  560. NULL,
  561. pDevContext,
  562. (USHORT) (SrcIsNameServer(SrcAddress,SrcPort) ?
  563. NAME_RESOLVED_BY_WINS:NAME_RESOLVED_BY_BCAST));
  564. //
  565. // this could delete the name so do not reference after this point
  566. //
  567. }
  568. status = STATUS_BAD_NETWORK_PATH;
  569. }
  570. //
  571. // Set the backup name server to be the main name server
  572. // since we got a response from it.
  573. // Bug# 95280: Do this only if the Primary Wins is down!
  574. //
  575. if ( (!(Flags & WINS_NEG_RESPONSE)) &&
  576. ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr
  577. == (ULONG)(htonl(pDeviceContext->lBackupServer)))
  578. {
  579. // switching the backup and the primary nameservers in
  580. // the config data structure since we got a name
  581. // registration response from the backup
  582. //
  583. SwitchToBackup(pDeviceContext);
  584. }
  585. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  586. // the completion routine has not run yet, so run it
  587. //
  588. #ifdef VXD
  589. //
  590. // chicago only has 4k of stack (yes, it's the operating system of 1995)
  591. // schedule an event to make this tcp connection later to reduce stack usage
  592. //
  593. CTEQueueForNonCritNonDispProcessing( DelayedSessEstablish,
  594. (tDGRAM_SEND_TRACKING *)Context,
  595. (PVOID)status,
  596. pClientCompletion,
  597. pDeviceContext);
  598. #else
  599. //
  600. // If pending is returned, we have submitted the check-for-addr request to lmhsvc.
  601. //
  602. if (status != STATUS_PENDING)
  603. {
  604. CompleteClientReq(pClientCompletion, (tDGRAM_SEND_TRACKING *)Context, status);
  605. }
  606. #endif
  607. return(STATUS_DATA_NOT_ACCEPTED);
  608. }
  609. else
  610. {
  611. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  612. }
  613. }
  614. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  615. }
  616. else if (!NbtConfig.MultiHomed)
  617. {
  618. // *** Name Query reponse ==> Name not on Pending list ***
  619. //
  620. // it is possible for two multihomed machines connected on two subnets
  621. // to respond on both subnets to a name query. Therefore the querying
  622. // multihomed machine will ultimately receive two name query responses
  623. // each with a different ip address and think that a name conflict has
  624. // occurred when it hasn't. There is no way to detect this case
  625. // so just disable the conflict detection code below. Conflicts will
  626. // still be detected by WINS and by the node owning the name if someone
  627. // else tries to get the name, but conflicts will no longer be detected
  628. // by third parties that have the name in their cache.
  629. // (Currently this case will be handled only if we are not multi-homed!)
  630. //
  631. //
  632. // This code implements a Conflict timer for name
  633. // queries. Look at name query response, and then send
  634. // name conflict demands to the subsequent responders.
  635. // There is no timer involved, and this node will always respond
  636. // negatively to name query responses sent to it, for names
  637. // it has in its remote cache, if the timer has been stopped.
  638. // ( meaning that one response has been successfully received ).
  639. //
  640. // The name is not in the NameQueryPending list, so check the
  641. // remote table.
  642. //
  643. status = FindInHashTable(NbtConfig.pRemoteHashTbl,
  644. pName,
  645. pScope,
  646. &pNameAddr);
  647. // check the src IP address and compare it to the one in the
  648. // remote hash table
  649. // Since it is possible for the name server to send a response
  650. // late, do not accidently respond to those as conflicts.
  651. // Since a bcast query of a group name will generally result in
  652. // multiple responses, each with a different address, ignore
  653. // this case.
  654. // Also, ignore if the name is a preloaded lmhosts entry (though
  655. // can't think of an obvious case where we would receive a response
  656. // when a name is preloaded!)
  657. //
  658. if (NT_SUCCESS(status) &&
  659. !(pNameAddr->NameTypeState & PRELOADED) &&
  660. (!IsRemoteAddress(pNameAddr, SrcAddress)) &&
  661. (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) &&
  662. (pNameAddr->NameTypeState & STATE_RESOLVED) &&
  663. (!IsNameServerForDevice (SrcAddress, pDeviceContext)))
  664. {
  665. //
  666. // Reference the name so that it doesn't disappear when
  667. // we are dereferencing it below! Bug# 233464
  668. //
  669. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_QUERY_RESPONSE);
  670. //
  671. // a different node is responding to the name query
  672. // so tell them to buzz off.
  673. //
  674. status = UdpSendResponse(
  675. lNameSize,
  676. pNameHdr,
  677. pNameAddr,
  678. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  679. pDeviceContext,
  680. CONFLICT_ERROR,
  681. eNAME_REGISTRATION_RESPONSE,
  682. OldIrq1);
  683. //
  684. // remove the name from the remote cache so the next time
  685. // we need to talk to it we do a name query
  686. //
  687. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  688. // set the name to the released state so that multiple
  689. // conflicting responses don't come in and decrement the
  690. // reference count to zero - in the case where some other
  691. // part of NBT is still using the name, that part of NBT
  692. // should do the final decrement - i.e. a datagram send to this
  693. // name.
  694. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  695. pNameAddr->NameTypeState |= STATE_RELEASED;
  696. //
  697. // don't deref if someone else is using it now...
  698. //
  699. if (pNameAddr->RefCount == 2)
  700. {
  701. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  702. }
  703. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_QUERY_RESPONSE, TRUE);
  704. }
  705. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  706. }
  707. else
  708. {
  709. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  710. }
  711. if (pQueryAddrs)
  712. {
  713. CTEFreeMem (pQueryAddrs);
  714. pQueryAddrs = NULL;
  715. }
  716. return(STATUS_DATA_NOT_ACCEPTED);
  717. }
  718. else // *** REQUEST ***
  719. {
  720. NTSTATUS Locstatus;
  721. //
  722. // check the pdu size for errors
  723. //
  724. if (lNumBytes < (FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize + 4))
  725. {
  726. // IF_DBG(NBT_DEBUG_NAMESRV)
  727. KdPrint (("Nbt.QueryFromNet[2]: WARNING!!! Rejecting Request -- lNumBytes=<%d> < <%d>\n",
  728. lNumBytes, (FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize + 4)));
  729. ASSERT(0);
  730. return(STATUS_DATA_NOT_ACCEPTED);
  731. }
  732. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  733. // call this routine
  734. // to see if the name is in the local table.
  735. //
  736. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  737. pName,
  738. pScope,
  739. &pNameAddr);
  740. pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  741. if (NT_SUCCESS(status) &&
  742. ((pNameAddr->NameTypeState & STATE_RESOLVED) ||
  743. (pNameAddr->NameTypeState & STATE_RESOLVING)))
  744. {
  745. //
  746. // check if this is a node status request, since is looks very similar
  747. // to a name query, except that the NBSTAT field is 0x21 instead of
  748. // 0x20
  749. //
  750. if ( ((PUCHAR)pQuery)[1] == QUEST_STATUS )
  751. {
  752. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  753. //
  754. // Reply only if this was not broadcast to us.
  755. //
  756. if (!fBroadcast)
  757. {
  758. Locstatus = SendNodeStatusResponse(pNameHdr,
  759. lNumBytes,
  760. pName,
  761. lNameSize,
  762. SrcAddress,
  763. SrcPort,
  764. pDeviceContext);
  765. }
  766. else
  767. {
  768. IF_DBG(NBT_DEBUG_NAMESRV)
  769. KdPrint(("NBT: Bcast nodestatus req.- dropped\n"));
  770. }
  771. }
  772. else
  773. {
  774. //
  775. // check if this message came from Us or it is not
  776. // a broadcast since WINS on this machine could send it.
  777. // Note: this check must be AFTER the check for a node status request
  778. // since we can send node status requests to ourselves.
  779. //
  780. if ((!SrcIsUs(SrcAddress)) ||
  781. (!(OpCodeFlags & FL_BROADCAST)
  782. #ifndef VXD
  783. && pWinsInfo
  784. #endif
  785. ))
  786. {
  787. //
  788. // build a positive name query response pdu
  789. //
  790. Locstatus = UdpSendResponse(
  791. lNameSize,
  792. pNameHdr,
  793. pNameAddr,
  794. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  795. pDeviceContext,
  796. 0,
  797. eNAME_QUERY_RESPONSE,
  798. OldIrq1);
  799. }
  800. else
  801. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  802. }
  803. return(STATUS_DATA_NOT_ACCEPTED);
  804. } else if (((PUCHAR)pQuery)[1] == QUEST_STATUS && !fBroadcast &&
  805. RtlCompareMemory(pName, NBT_BROADCAST_NAME, NETBIOS_NAMESIZE) == NETBIOS_NAMESIZE) {
  806. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  807. Locstatus = SendNodeStatusResponse(pNameHdr,
  808. lNumBytes,
  809. pName,
  810. lNameSize,
  811. SrcAddress,
  812. SrcPort,
  813. pDeviceContext);
  814. return(STATUS_DATA_NOT_ACCEPTED);
  815. }
  816. else if ( !(OpCodeFlags & FL_BROADCAST) )
  817. {
  818. // Build a negative response if this query was directed rather than
  819. // broadcast (since we do not want to Nack all broadcasts!)
  820. // check that it is not a node status request...
  821. //
  822. pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  823. if ( ((PUCHAR)pQuery)[1] == QUEST_NETBIOS )
  824. {
  825. Locstatus = UdpSendResponse(
  826. lNameSize,
  827. pNameHdr,
  828. NULL,
  829. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  830. pDeviceContext,
  831. 0,
  832. eNAME_QUERY_RESPONSE,
  833. OldIrq1);
  834. }
  835. else
  836. {
  837. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  838. }
  839. return(STATUS_DATA_NOT_ACCEPTED);
  840. }
  841. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  842. #ifdef PROXY_NODE
  843. //
  844. // check if this message came from Us !! (and return if so)
  845. //
  846. if (SrcIsUs(SrcAddress))
  847. {
  848. return(STATUS_DATA_NOT_ACCEPTED);
  849. }
  850. pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  851. IF_PROXY(NodeType)
  852. {
  853. // check that it is not a node status request...
  854. if (((PUCHAR)pQuery)[1] == QUEST_NETBIOS )
  855. {
  856. //
  857. // We have a broadcast name query request for a name that
  858. // is not in our local name table. If we are a proxy we need
  859. // to resolve the query if not already resolved and respond
  860. // with the address(es) to the node that sent the query.
  861. //
  862. // Note: We will respond only if the address that the name
  863. // resolves to is not on our subnet. For our own subnet addresses
  864. // the node that has the address will respond.
  865. //
  866. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  867. //
  868. // call this routine which looks for names without regard
  869. // to their state
  870. //
  871. status = FindInHashTable(NbtConfig.pRemoteHashTbl,
  872. pName,
  873. pScope,
  874. &pNameAddr);
  875. if (!NT_SUCCESS(status))
  876. {
  877. status = FindOnPendingList(pName,pNameHdr,TRUE,NETBIOS_NAME_SIZE,&pNameAddr);
  878. if (!NT_SUCCESS(status))
  879. {
  880. //
  881. // cache the name and contact the name
  882. // server to get the name to IP mapping
  883. //
  884. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  885. status = RegOrQueryFromNet(
  886. FALSE, //means it is a name query
  887. pDeviceContext,
  888. pNameHdr,
  889. lNameSize,
  890. pName,
  891. pScope);
  892. return(STATUS_DATA_NOT_ACCEPTED);
  893. }
  894. else
  895. {
  896. //
  897. // the name is on the pending list doing a name query
  898. // now, so ignore this name query request
  899. //
  900. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  901. return(STATUS_DATA_NOT_ACCEPTED);
  902. }
  903. }
  904. else
  905. {
  906. //
  907. // The name can be in the RESOLVED, RESOLVING or RELEASED
  908. // state.
  909. //
  910. //
  911. // If in the RELEASED state, its reference count has to be
  912. // > 0
  913. //
  914. //ASSERT(pNameAddr->NameTypeState & (STATE_RESOLVED | STATE_RESOLVING) || (pNameAddr->NameTypeState & STATE_RELEASED) && (pNameAddr->RefCount > 0));
  915. //
  916. // Send a response only if the name is in the RESOLVED state
  917. //
  918. if (pNameAddr->NameTypeState & STATE_RESOLVED)
  919. {
  920. //
  921. // The PROXY sends a response if the address of the
  922. // node queries is not on the same subnet as the
  923. // node doing the query (or as us). It also responds
  924. // if the name is a group name or if it belongs to
  925. // a Pnode. Note: In theory there is no reason to
  926. // respond for group names since a member of the group
  927. // on the subnet will respond with their address if they
  928. // are alive - if they are B or M nodes - perhaps
  929. // the fPnode bit is not set correctly for groups, so
  930. // therefore always respond in case all the members
  931. // are pnodes.
  932. //
  933. //
  934. // If we have multiple network addresses in the same
  935. // broadcast area, then this test won't be sufficient
  936. //
  937. if (
  938. ((SrcAddress & pDeviceContext->SubnetMask)
  939. !=
  940. (pNameAddr->IpAddress & pDeviceContext->SubnetMask))
  941. ||
  942. (pNameAddr->fPnode)
  943. ||
  944. !(pNameAddr->NameTypeState & NAMETYPE_UNIQUE)
  945. )
  946. {
  947. IF_DBG(NBT_DEBUG_PROXY)
  948. KdPrint(("QueryFromNet: QUERY SATISFIED by PROXY CACHE -- name is %16.16s(%X); %s entry ; Address is (%d)\n",
  949. pNameAddr->Name,pNameAddr->Name[15], (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ? "UNIQUE" : "INET_GROUP",
  950. pNameAddr->IpAddress));
  951. //
  952. //build a positive name query response pdu
  953. //
  954. // UdpSendQueryResponse frees the spin lock
  955. //
  956. status = UdpSendResponse(
  957. lNameSize,
  958. pNameHdr,
  959. pNameAddr,
  960. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  961. pDeviceContext,
  962. 0,
  963. eNAME_QUERY_RESPONSE,
  964. OldIrq1);
  965. return(STATUS_DATA_NOT_ACCEPTED);
  966. }
  967. }
  968. else
  969. {
  970. IF_DBG(NBT_DEBUG_PROXY)
  971. KdPrint(("QueryFromNet: REQUEST for Name %16.16s(%X) in %s state\n", pNameAddr->Name, pNameAddr->Name[15],( pNameAddr->NameTypeState & STATE_RELEASED ? "RELEASED" : "RESOLVING")));
  972. }
  973. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  974. return(STATUS_DATA_NOT_ACCEPTED);
  975. }
  976. }
  977. } // end of proxy code
  978. #endif
  979. } // end of else (it is a name query request)
  980. return(STATUS_DATA_NOT_ACCEPTED);
  981. }
  982. //----------------------------------------------------------------------------
  983. NTSTATUS
  984. RegResponseFromNet(
  985. IN tDEVICECONTEXT *pDeviceContext,
  986. IN PVOID pSrcAddress,
  987. IN tNAMEHDR UNALIGNED *pNameHdr,
  988. IN LONG lNumBytes,
  989. IN USHORT OpCodeFlags
  990. )
  991. /*++
  992. Routine Description:
  993. This routine handles name registration responses from the net (i.e. from
  994. the name server most of the time since a broadcast name registration passes
  995. when there is no response.
  996. ***
  997. The response could be from an NBT node when it notices that the name
  998. registration is for a name that it has already claimed - i.e. the node
  999. is sending a NAME_CONFLICT_DEMAND - in this case the Rcode in the PDU
  1000. will be CFT_ERR = 7.
  1001. Arguments:
  1002. Return Value:
  1003. NTSTATUS - success or not - failure means no response to net
  1004. --*/
  1005. {
  1006. NTSTATUS status;
  1007. ULONG lNameSize;
  1008. CHAR pName[NETBIOS_NAME_SIZE];
  1009. PUCHAR pScope;
  1010. tNAMEADDR *pNameAddr; //Get rid of this later. Use pNameAddr
  1011. tTIMERQENTRY *pTimer;
  1012. COMPLETIONCLIENT pClientCompletion;
  1013. PVOID Context;
  1014. PTRANSPORT_ADDRESS pSourceAddress;
  1015. CTELockHandle OldIrq1;
  1016. ULONG SrcAddress;
  1017. SHORT SrcPort;
  1018. pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
  1019. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  1020. SrcPort = ntohs(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port);
  1021. //
  1022. // be sure the Pdu is at least a minimum size
  1023. //
  1024. if (lNumBytes < (NBT_MINIMUM_REGRESPONSE + NbtConfig.ScopeLength -1))
  1025. {
  1026. IF_DBG(NBT_DEBUG_NAMESRV)
  1027. KdPrint(("Nbt:Registration Response TOO short = %X, Src = %X\n",
  1028. lNumBytes,SrcAddress));
  1029. IF_DBG(NBT_DEBUG_NAMESRV)
  1030. KdPrint(("%.*X\n",lNumBytes/sizeof(ULONG),pNameHdr));
  1031. return(STATUS_DATA_NOT_ACCEPTED);
  1032. }
  1033. //
  1034. // if Wins is locally attached then we will get registrations from
  1035. // ourselves!!
  1036. //
  1037. if (SrcIsUs(SrcAddress)
  1038. #ifndef VXD
  1039. && !pWinsInfo
  1040. #endif
  1041. )
  1042. {
  1043. return(STATUS_DATA_NOT_ACCEPTED);
  1044. }
  1045. // get the name out of the network pdu and pass to routine to check
  1046. // local table *TODO* this assumes just one name in the Query response...
  1047. // We need to handle group lists from the WINS server
  1048. status = ConvertToAscii(
  1049. (PCHAR)&pNameHdr->NameRR,
  1050. lNumBytes - FIELD_OFFSET(tNAMEHDR,NameRR),
  1051. pName,
  1052. &pScope,
  1053. &lNameSize);
  1054. if (!NT_SUCCESS(status))
  1055. {
  1056. // IF_DBG(NBT_DEBUG_NAMESRV)
  1057. KdPrint (("Nbt.RegResponseFromNet: WARNING!!! Rejecting Request -- ConvertToAscii FAILed\n"));
  1058. return(STATUS_DATA_NOT_ACCEPTED);
  1059. }
  1060. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1061. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  1062. pName,
  1063. pScope,
  1064. &pNameAddr);
  1065. if (NT_SUCCESS(status) &&
  1066. (pNameAddr->AdapterMask & pDeviceContext->AdapterMask))
  1067. {
  1068. NTSTATUS Localstatus;
  1069. //
  1070. // check the state of the name since this could be a registration
  1071. // response or a name conflict demand
  1072. //
  1073. switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
  1074. {
  1075. case STATE_CONFLICT:
  1076. //
  1077. // We only allow this state if we are currently trying to
  1078. // get ourselves out of a Conflict scenario
  1079. // We need to distinguish from the case where the name is
  1080. // in conflict due to being dereferenced out
  1081. //
  1082. if (!pNameAddr->pAddressEle)
  1083. {
  1084. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1085. break;
  1086. }
  1087. case STATE_RESOLVING:
  1088. case STATE_RESOLVED:
  1089. if (IS_POS_RESPONSE(OpCodeFlags))
  1090. {
  1091. if (OpCodeFlags & FL_RECURAVAIL)
  1092. {
  1093. // turn on the refreshed bit in NextRefresh now
  1094. // (when the timer completion routine is called)
  1095. // only count names registered, not REFRESHES too!
  1096. //
  1097. if (pNameAddr->NameTypeState & STATE_RESOLVING)
  1098. {
  1099. IncrementNameStats(NAME_REGISTRATION_SUCCESS,
  1100. SrcIsNameServer(SrcAddress,SrcPort));
  1101. }
  1102. status = STATUS_SUCCESS;
  1103. }
  1104. else
  1105. {
  1106. //
  1107. // in this case the name server is telling this node
  1108. // to do an end node challenge on the name. However
  1109. // this node does not have the code to do a challenge
  1110. // so assume that this is a positive registration
  1111. // response.
  1112. //
  1113. status = STATUS_SUCCESS;
  1114. }
  1115. }
  1116. else if (!SrcIsNameServer(SrcAddress,SrcPort) && pNameAddr->pTimer == NULL) {
  1117. //
  1118. // 05/17/00 Fix "a malicious user can flush a cache entry by sending a unsolicited negative response"
  1119. // Drop the response if it is not from a name server and runs out of time
  1120. //
  1121. status = STATUS_DATA_NOT_ACCEPTED;
  1122. KdPrint(("Waring: discard a timeout registration response from a non-namesever\n"));
  1123. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1124. NbtLogEvent (EVENT_NBT_DUPLICATE_NAME, SrcAddress, 0x105);
  1125. break;
  1126. }
  1127. else if ((OpCodeFlags & FL_RCODE) >= FL_NAME_ACTIVE)
  1128. {
  1129. // if we are multihomed, then we only allow the name server
  1130. // to send Name Active errors, since in normal operation this node
  1131. // could generate two different IP address for the same name
  1132. // query and confuse another client node into sending a Name
  1133. // Conflict. So jump out if a name conflict has been received
  1134. // from another node.
  1135. //
  1136. if ((NbtConfig.MultiHomed) &&
  1137. ((OpCodeFlags & FL_RCODE) == FL_NAME_CONFLICT))
  1138. {
  1139. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1140. break;
  1141. }
  1142. if (!IS_MESSENGER_NAME(pNameAddr->Name))
  1143. {
  1144. //
  1145. // We need to Q this event to a Worker thread since it
  1146. // requires the name to be converted to Unicode
  1147. //
  1148. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT);
  1149. status = NTQueueToWorkerThread(
  1150. NULL,
  1151. DelayedNbtLogDuplicateNameEvent,
  1152. (PVOID) pNameAddr,
  1153. IntToPtr(SrcAddress),
  1154. IntToPtr(0x101),
  1155. pDeviceContext,
  1156. TRUE);
  1157. if (!NT_SUCCESS(status))
  1158. {
  1159. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT, TRUE);
  1160. NbtLogEvent (EVENT_NBT_DUPLICATE_NAME, SrcAddress, 0x101);
  1161. }
  1162. }
  1163. status = STATUS_DUPLICATE_NAME;
  1164. //
  1165. // if the name is resolved and we get a negative response
  1166. // then mark the name as in the conflict state so it can't
  1167. // be used for any new sessions and this node will no longer
  1168. // defend it.
  1169. //
  1170. if (pNameAddr->NameTypeState & STATE_RESOLVED)
  1171. {
  1172. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  1173. pNameAddr->NameTypeState |= STATE_CONFLICT;
  1174. pNameAddr->ConflictMask |= pDeviceContext->AdapterMask;
  1175. }
  1176. }
  1177. else
  1178. {
  1179. //
  1180. // we got some kind of WINS server failure ret code
  1181. // so just ignore it and assume the name registration
  1182. // succeeded.
  1183. //
  1184. status = STATUS_SUCCESS;
  1185. }
  1186. // remove any timer block and call the completion routine
  1187. // if the name is in the Resolving state only
  1188. //
  1189. LOCATION(0x40);
  1190. if ((pTimer = pNameAddr->pTimer))
  1191. {
  1192. tDGRAM_SEND_TRACKING *pTracker;
  1193. USHORT SendTransactId;
  1194. tDEVICECONTEXT *pDevContext;
  1195. // check the transaction id to be sure it is the same as the one
  1196. // sent.
  1197. //
  1198. LOCATION(0x41);
  1199. pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
  1200. SendTransactId = pTracker->TransactionId;
  1201. pDevContext = pTracker->pDeviceContext;
  1202. if (pNameHdr->TransactId != SendTransactId)
  1203. {
  1204. LOCATION(0x42);
  1205. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1206. return(STATUS_DATA_NOT_ACCEPTED);
  1207. }
  1208. LOCATION(0x43);
  1209. CHECK_PTR(pNameAddr);
  1210. //
  1211. // This could be either a Refresh or a name registration. In
  1212. // either case, stop the timer and call the completion routine
  1213. // for the client.(below).
  1214. //
  1215. pNameAddr->pTimer = NULL;
  1216. Localstatus = StopTimer(pTimer,&pClientCompletion,&Context);
  1217. // check if it is a response from the name server
  1218. // and a M, or P or MS node, since we will need to send
  1219. // refreshes to the name server for these node types
  1220. //
  1221. pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
  1222. // only accept pdus from the name server to change the Ttl.
  1223. // The first check passes the case where WINS is on this machine
  1224. //
  1225. if (
  1226. #ifndef VXD
  1227. (pWinsInfo && (SrcIsUs (SrcAddress))) ||
  1228. #endif
  1229. (SrcAddress == pDeviceContext->lNameServerAddress))
  1230. {
  1231. if (!(NodeType & BNODE) &&
  1232. (status == STATUS_SUCCESS) &&
  1233. (IS_POS_RESPONSE(OpCodeFlags)))
  1234. {
  1235. SetupRefreshTtl(pNameHdr,pNameAddr,lNameSize);
  1236. // a name refresh response if in the resolved state
  1237. }
  1238. }
  1239. else if ( SrcAddress == pDeviceContext->lBackupServer)
  1240. {
  1241. // switching the backup and the primary nameservers in
  1242. // the config data structure since we got a name
  1243. // registration response from the backup
  1244. //
  1245. SwitchToBackup(pDeviceContext);
  1246. if (!(NodeType & BNODE) &&
  1247. (status == STATUS_SUCCESS) &&
  1248. (IS_POS_RESPONSE(OpCodeFlags)))
  1249. {
  1250. SetupRefreshTtl(pNameHdr,pNameAddr,lNameSize);
  1251. }
  1252. }
  1253. //
  1254. // mark name as refreshed if we got through to WINS Ok
  1255. //
  1256. if ((pClientCompletion) && (IS_POS_RESPONSE(OpCodeFlags)))
  1257. {
  1258. pNameAddr->RefreshMask |= pDevContext->AdapterMask;
  1259. }
  1260. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1261. // the completion routine has not run yet, so run it - this
  1262. // is the Registration Completion routine and we DO want it to
  1263. // run to mark the entry refreshed (NextRefresh)
  1264. if (pClientCompletion)
  1265. {
  1266. LOCATION(0x44);
  1267. (*pClientCompletion)(Context,status);
  1268. }
  1269. }
  1270. else
  1271. {
  1272. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1273. }
  1274. break;
  1275. default:
  1276. //
  1277. // if multiple (neg)registration responses are received, subsequent ones
  1278. // after the first will go through this path because the state of
  1279. // the name will have been changed by the first to CONFLICT
  1280. //
  1281. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1282. }
  1283. }
  1284. else
  1285. {
  1286. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1287. } // end of else block (If name is not in local table)
  1288. return(STATUS_DATA_NOT_ACCEPTED);
  1289. }
  1290. //----------------------------------------------------------------------------
  1291. NTSTATUS
  1292. CheckRegistrationFromNet(
  1293. IN tDEVICECONTEXT *pDeviceContext,
  1294. IN PVOID pSrcAddress,
  1295. IN tNAMEHDR UNALIGNED *pNameHdr,
  1296. IN LONG lNumBytes
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine handles name registrations from the network that are
  1301. potentially duplicates of names in the local name table. It compares
  1302. name registrations against its local table and defends any attempts to
  1303. take a name that is owned by this node. This routine handles name registration
  1304. REQUESTS.
  1305. Arguments:
  1306. Return Value:
  1307. NTSTATUS - success or not - failure means no response to net
  1308. --*/
  1309. {
  1310. NTSTATUS status;
  1311. ULONG lNameSize;
  1312. CHAR pName[NETBIOS_NAME_SIZE];
  1313. PUCHAR pScope;
  1314. tNAMEADDR *pNameAddr;
  1315. tTIMERQENTRY *pTimer;
  1316. PTRANSPORT_ADDRESS pSourceAddress;
  1317. USHORT RegType;
  1318. CTELockHandle OldIrq1;
  1319. ULONG SrcAddress;
  1320. pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
  1321. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  1322. //
  1323. // check the pdu size for errors
  1324. //
  1325. if (lNumBytes < (NBT_MINIMUM_REGREQUEST + (NbtConfig.ScopeLength-1)))
  1326. {
  1327. IF_DBG(NBT_DEBUG_NAMESRV)
  1328. KdPrint(("Nbt:Registration Request TOO short = %X,Src = %X\n", lNumBytes,SrcAddress));
  1329. IF_DBG(NBT_DEBUG_NAMESRV)
  1330. KdPrint(("%.*X\n",lNumBytes/sizeof(ULONG),pNameHdr));
  1331. return(STATUS_DATA_NOT_ACCEPTED);
  1332. }
  1333. //
  1334. // check if this message came from Us !! (and return if so)
  1335. //
  1336. if (SrcIsUs(SrcAddress))
  1337. {
  1338. return(STATUS_DATA_NOT_ACCEPTED);
  1339. }
  1340. // get the name out of the network pdu and pass to routine to check
  1341. // local table *TODO* this assumes just one name in the Query response...
  1342. status = ConvertToAscii(
  1343. (PCHAR)&pNameHdr->NameRR,
  1344. lNumBytes - FIELD_OFFSET(tNAMEHDR,NameRR),
  1345. pName,
  1346. &pScope,
  1347. &lNameSize);
  1348. if (!NT_SUCCESS(status))
  1349. {
  1350. // IF_DBG(NBT_DEBUG_NAMESRV)
  1351. KdPrint (("Nbt.CheckRegistrationFromNet: WARNING! Rejecting Request -- ConvertToAscii FAILed\n"));
  1352. return(STATUS_DATA_NOT_ACCEPTED);
  1353. }
  1354. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1355. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  1356. pName,
  1357. pScope,
  1358. &pNameAddr);
  1359. if (NT_SUCCESS(status))
  1360. {
  1361. // don't defend the broadcast name
  1362. if ((pName[0] == '*') ||
  1363. (STATUS_SUCCESS != GetNbFlags (pNameHdr, lNameSize, lNumBytes, &RegType)))
  1364. {
  1365. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1366. // IF_DBG(NBT_DEBUG_NAMESRV)
  1367. KdPrint (("Nbt.CheckRegistrationFromNet: WARNING! Rejecting Request -- GetNbFlags FAILed\n"));
  1368. return(STATUS_DATA_NOT_ACCEPTED);
  1369. }
  1370. // we defend against anyone trying to take a unique name, or anyone
  1371. // trying to register a unique name for a group name we have. - if
  1372. // the name is registered on this adapter
  1373. //
  1374. if (((pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ||
  1375. ((pNameAddr->NameTypeState & NAMETYPE_GROUP) &&
  1376. ((RegType & FL_GROUP) == 0))) &&
  1377. (pNameAddr->AdapterMask & pDeviceContext->AdapterMask))
  1378. {
  1379. //
  1380. // check the state of the name since this could be registration
  1381. // for the same name while we are registering the name. If another
  1382. // node claims the name at the same time, then cancel the name
  1383. // registration.
  1384. //
  1385. switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
  1386. {
  1387. case STATE_RESOLVING:
  1388. CHECK_PTR(pNameAddr);
  1389. // remove any timer block and call the completion routine
  1390. if ((pTimer = pNameAddr->pTimer))
  1391. {
  1392. COMPLETIONCLIENT pClientCompletion;
  1393. PVOID Context;
  1394. pNameAddr->pTimer = NULL;
  1395. status = StopTimer(pTimer,&pClientCompletion,&Context);
  1396. if (pClientCompletion)
  1397. {
  1398. if (!IS_MESSENGER_NAME(pNameAddr->Name))
  1399. {
  1400. //
  1401. // We need to Q this event to a Worker thread since it
  1402. // requires the name to be converted to Unicode
  1403. //
  1404. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT);
  1405. status = NTQueueToWorkerThread(
  1406. NULL,
  1407. DelayedNbtLogDuplicateNameEvent,
  1408. (PVOID) pNameAddr,
  1409. IntToPtr(SrcAddress),
  1410. IntToPtr(0x102),
  1411. pDeviceContext,
  1412. TRUE);
  1413. if (!NT_SUCCESS(status))
  1414. {
  1415. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_LOG_EVENT, TRUE);
  1416. NbtLogEvent (EVENT_NBT_DUPLICATE_NAME, SrcAddress, 0x102);
  1417. }
  1418. }
  1419. status = STATUS_DUPLICATE_NAME; // CHANGE the state of the entry
  1420. // the completion routine has not run yet, so run it
  1421. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1422. (*pClientCompletion)(Context,status);
  1423. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1424. }
  1425. }
  1426. break;
  1427. case STATE_RESOLVED:
  1428. //
  1429. // We must defend our name against this Rogue attempting to steal
  1430. // our Name! ( unless the name is "*")
  1431. //
  1432. status = UdpSendResponse(
  1433. lNameSize,
  1434. pNameHdr,
  1435. pNameAddr,
  1436. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  1437. pDeviceContext,
  1438. REGISTRATION_ACTIVE_ERR,
  1439. eNAME_REGISTRATION_RESPONSE,
  1440. OldIrq1);
  1441. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1442. break;
  1443. }
  1444. }
  1445. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1446. }
  1447. else
  1448. {
  1449. //
  1450. // NOTE: We have the Joint Lock
  1451. //
  1452. //
  1453. // The name is not in the local name table, so check if the proxy is
  1454. // on and if we want the proxy to check name registrations. The
  1455. // trouble with checking name registrations is that the proxy code
  1456. // only does a name query, so it will fail any node that is trying
  1457. // to change its address such as a RAS client coming in on a downlevel
  1458. // NT machine that only does broadcast name registrations. If
  1459. // that same user had previously dialled in on a WINS supporting RAS
  1460. // machine, their address would be in WINS, then dialling in on the
  1461. // downlevel machine would find that 'old' registration and deny
  1462. // the new one ( even though it is the same machine just changing
  1463. // its ip address).
  1464. //
  1465. #ifdef PROXY_NODE
  1466. if ((NodeType & PROXY) &&
  1467. (NbtConfig.EnableProxyRegCheck))
  1468. {
  1469. BOOLEAN fResp = (BOOLEAN)FALSE;
  1470. //
  1471. // If name is RESOLVED in the remote table, has a different
  1472. // address than the node claiming the name, is not on the
  1473. // same subnet or is a Pnode then send a negative name
  1474. // registration response
  1475. //
  1476. //
  1477. // call this routine to find the name, since it does not
  1478. // interpret the state of the name as does FindName()
  1479. //
  1480. status = FindInHashTable(NbtConfig.pRemoteHashTbl,
  1481. pName,
  1482. pScope,
  1483. &pNameAddr);
  1484. if (!NT_SUCCESS(status))
  1485. {
  1486. //
  1487. // We need to send a query to WINS to
  1488. // see if the name is already taken or not.
  1489. //
  1490. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1491. status = RegOrQueryFromNet(
  1492. TRUE, //means it is a reg. from the net
  1493. pDeviceContext,
  1494. pNameHdr,
  1495. lNameSize,
  1496. pName,
  1497. pScope
  1498. );
  1499. return(STATUS_DATA_NOT_ACCEPTED);
  1500. }
  1501. //
  1502. // If the name is in the RESOLVED state, we need to determine
  1503. // whether we should respond or not. For a name that is not
  1504. // the RESOLVED state, the decision is simple. We don't respond
  1505. if (pNameAddr->NameTypeState & STATE_RESOLVED)
  1506. {
  1507. ULONG IPAdd;
  1508. if (STATUS_SUCCESS != GetNbFlags(pNameHdr, lNameSize, lNumBytes, &RegType))
  1509. {
  1510. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1511. // IF_DBG(NBT_DEBUG_NAMESRV)
  1512. KdPrint (("Nbt.CheckRegistrationFromNet[2]: WARNING! Rejecting Request -- GetNbFlags FAILed\n"));
  1513. return (STATUS_DATA_NOT_ACCEPTED);
  1514. }
  1515. //
  1516. // If a unique name is being registered but our cache shows
  1517. // the name to be a group name (normal or internet), we
  1518. // send a negative name registration response.
  1519. //
  1520. // If a node on the same subnet has responded negatively also,
  1521. // it is ok. It is possible that WINS/NBNS has old
  1522. // information but there is no easy way to determine the
  1523. // network address of the node that registered the group.
  1524. // (For a normal group, there could have been several
  1525. // nodes that registered it -- their addresses are not stored
  1526. // by WINS.
  1527. //
  1528. if (!(RegType & FL_GROUP) &&
  1529. !(pNameAddr->NameTypeState & NAMETYPE_UNIQUE))
  1530. {
  1531. fResp = TRUE;
  1532. }
  1533. else
  1534. {
  1535. tGENERALRR UNALIGNED *pResrcRecord;
  1536. // get the Ip address out of the Registration request
  1537. pResrcRecord = (tGENERALRR *) &pNameHdr->NameRR.NetBiosName[lNameSize];
  1538. IPAdd = ntohl(pResrcRecord->IpAddress);
  1539. //
  1540. // If a group name is being registered but our cache shows
  1541. // the name to be a unique name (normal or internet) or
  1542. // if a UNIQUE name is being registered but clashes with
  1543. // a unique name with a different address, we check if the
  1544. // the addresses belong to the same subnet. If they do, we
  1545. // don't respond, else we send a negative registration
  1546. // response.
  1547. //
  1548. // Note: We never respond to a group registration
  1549. // that clashes with a group name in our cache.
  1550. //
  1551. if (((RegType & FL_GROUP)
  1552. &&
  1553. (pNameAddr->NameTypeState & NAMETYPE_UNIQUE))
  1554. ||
  1555. (!(RegType & FL_GROUP)
  1556. &&
  1557. (pNameAddr->NameTypeState & NAMETYPE_UNIQUE)
  1558. &&
  1559. IPAdd != pNameAddr->IpAddress))
  1560. {
  1561. IF_DBG(NBT_DEBUG_PROXY)
  1562. KdPrint(("CheckReg:Subnet Mask = (%x)\nIPAdd=(%x)\npNameAddr->IPAdd = (%x)\npNameAddr->fPnode=(%d)\nIt is %s name %16.16s(%X)\nRegType Of Name Recd is %x\n---------------\n",
  1563. pDeviceContext->SubnetMask, IPAdd, pNameAddr->IpAddress,
  1564. pNameAddr->fPnode,
  1565. pNameAddr->NameTypeState & NAMETYPE_GROUP ? "GROUP" : "UNIQUE",
  1566. pName, pName[15], RegType));
  1567. //
  1568. // Are the querying node and the queried node on the
  1569. // same subnet ?
  1570. //
  1571. if (((IPAdd & pDeviceContext->SubnetMask)
  1572. !=
  1573. (pNameAddr->IpAddress & pDeviceContext->SubnetMask))
  1574. ||
  1575. (pNameAddr->fPnode))
  1576. {
  1577. fResp = TRUE;
  1578. }
  1579. }
  1580. }
  1581. //
  1582. // If a negative response needs to be sent, send it now
  1583. //
  1584. if (fResp)
  1585. {
  1586. IF_DBG(NBT_DEBUG_PROXY)
  1587. KdPrint(("CheckRegistrationFromNet: Sending a negative name registration response for name %16.16s(%X) to node with address (%d)\n",
  1588. pNameAddr->Name, pNameAddr->Name[15], IPAdd));
  1589. //
  1590. // a different node is responding to the name query
  1591. // so tell them to buzz off.
  1592. //
  1593. status = UdpSendResponse(
  1594. lNameSize,
  1595. pNameHdr,
  1596. pNameAddr,
  1597. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  1598. pDeviceContext,
  1599. REGISTRATION_ACTIVE_ERR,
  1600. eNAME_REGISTRATION_RESPONSE,
  1601. OldIrq1);
  1602. return(STATUS_DATA_NOT_ACCEPTED);
  1603. }
  1604. } // end of if (NAME is in the RESOLVED state)
  1605. }
  1606. #endif
  1607. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1608. }
  1609. return(STATUS_DATA_NOT_ACCEPTED);
  1610. }
  1611. //----------------------------------------------------------------------------
  1612. NTSTATUS
  1613. NameReleaseFromNet(
  1614. IN tDEVICECONTEXT *pDeviceContext,
  1615. IN PVOID pSrcAddress,
  1616. IN tNAMEHDR UNALIGNED *pNameHdr,
  1617. IN LONG lNumBytes
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. This routine handles name releases that arrive from the Net. The idea
  1622. is to delete the name from the remote cache if it exists there so that
  1623. this node does not erroneously use that cached information anymore.
  1624. Arguments:
  1625. Return Value:
  1626. NTSTATUS - success or not - failure means no response to net
  1627. --*/
  1628. {
  1629. NTSTATUS status;
  1630. LONG lNameSize;
  1631. CHAR pName[NETBIOS_NAME_SIZE];
  1632. PUCHAR pScope;
  1633. tNAMEADDR *pNameAddr;
  1634. PTRANSPORT_ADDRESS pSourceAddress;
  1635. CTELockHandle OldIrq1;
  1636. USHORT OpCodeFlags;
  1637. tTIMERQENTRY *pTimer;
  1638. ULONG SrcAddress;
  1639. ULONG Flags;
  1640. USHORT SendTransactId;
  1641. tDGRAM_SEND_TRACKING *pTracker;
  1642. BOOLEAN bLocalTable;
  1643. tGENERALRR UNALIGNED *pRemainder;
  1644. USHORT SrcPort;
  1645. ULONG Rcode;
  1646. pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
  1647. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  1648. SrcPort = ntohs(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port);
  1649. //
  1650. // check if we should not release our names on demand
  1651. //
  1652. if (NbtConfig.NoNameReleaseOnDemand) {
  1653. return(STATUS_DATA_NOT_ACCEPTED);
  1654. }
  1655. //
  1656. // check the pdu size for errors
  1657. //
  1658. if (lNumBytes < (NBT_MINIMUM_REGRESPONSE + NbtConfig.ScopeLength -1))
  1659. {
  1660. IF_DBG(NBT_DEBUG_NAMESRV)
  1661. KdPrint(("Nbt:Release Request/Response TOO short = %X, Src = %X\n",lNumBytes,
  1662. SrcAddress));
  1663. IF_DBG(NBT_DEBUG_NAMESRV)
  1664. KdPrint(("%.*X\n",lNumBytes/sizeof(ULONG),pNameHdr));
  1665. return(STATUS_DATA_NOT_ACCEPTED);
  1666. }
  1667. //
  1668. // check if this message came from Us !!
  1669. //
  1670. if (SrcIsUs(SrcAddress))
  1671. {
  1672. return(STATUS_DATA_NOT_ACCEPTED);
  1673. }
  1674. // get the name out of the network pdu and pass to routine to check
  1675. status = ConvertToAscii(
  1676. (PCHAR)&pNameHdr->NameRR,
  1677. lNumBytes - FIELD_OFFSET(tNAMEHDR,NameRR),
  1678. pName,
  1679. &pScope,
  1680. &lNameSize);
  1681. if (!NT_SUCCESS(status))
  1682. {
  1683. // IF_DBG(NBT_DEBUG_NAMESRV)
  1684. KdPrint (("Nbt.NameReleaseFromNet: WARNING!!! Rejecting Request -- ConvertToAscii FAILed\n"));
  1685. return(STATUS_DATA_NOT_ACCEPTED);
  1686. }
  1687. OpCodeFlags = pNameHdr->OpCodeFlags;
  1688. pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
  1689. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  1690. //
  1691. // *** RESPONSE ***
  1692. //
  1693. if (OpCodeFlags & OP_RESPONSE)
  1694. {
  1695. //
  1696. // call this routine to find the name, since it does not interpret the
  1697. // state of the name as does FindName()
  1698. //
  1699. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1700. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  1701. pName,
  1702. pScope,
  1703. &pNameAddr);
  1704. if (!NT_SUCCESS(status))
  1705. {
  1706. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1707. return(STATUS_DATA_NOT_ACCEPTED);
  1708. }
  1709. // Get the Timer block
  1710. if (!(pTimer = pNameAddr->pTimer))
  1711. {
  1712. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1713. return(STATUS_DATA_NOT_ACCEPTED);
  1714. }
  1715. //
  1716. // the name server is responding to a name release request
  1717. //
  1718. // check the transaction id to be sure it is the same as the one
  1719. // sent.
  1720. //
  1721. pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
  1722. SendTransactId = pTracker->TransactionId;
  1723. if (pNameHdr->TransactId != SendTransactId)
  1724. {
  1725. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1726. return(STATUS_DATA_NOT_ACCEPTED);
  1727. }
  1728. // for MS & M nodes if there is a response from the name server,
  1729. // then switch to broadcast name release.
  1730. //
  1731. //
  1732. switch (NodeType & NODE_MASK)
  1733. {
  1734. case MNODE:
  1735. case MSNODE:
  1736. if (SrcIsNameServer(SrcAddress,SrcPort))
  1737. {
  1738. Flags = pTracker->Flags;
  1739. if (Flags & NBT_NAME_SERVER)
  1740. {
  1741. //
  1742. // the next timeout will then switch to broadcast name
  1743. // release.
  1744. //
  1745. pTimer->Retries = 1;
  1746. }
  1747. }
  1748. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1749. return(STATUS_DATA_NOT_ACCEPTED);
  1750. case PNODE:
  1751. //
  1752. //
  1753. // this routine puts the timer block back on the timer Q, and
  1754. // handles race conditions to cancel the timer when the timer
  1755. // is expiring.
  1756. //
  1757. if ((pTimer = pNameAddr->pTimer))
  1758. {
  1759. COMPLETIONCLIENT pClientCompletion;
  1760. PVOID Context;
  1761. CHECK_PTR(pNameAddr);
  1762. pNameAddr->pTimer = NULL;
  1763. status = StopTimer(pTimer,&pClientCompletion,&Context);
  1764. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1765. // the completion routine has not run yet, so run it
  1766. if (pClientCompletion)
  1767. {
  1768. (*pClientCompletion)(Context,STATUS_SUCCESS);
  1769. }
  1770. }
  1771. else
  1772. {
  1773. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1774. }
  1775. return(STATUS_DATA_NOT_ACCEPTED);
  1776. case BNODE:
  1777. default:
  1778. //
  1779. // normally there should be no response to a name release
  1780. // from a Bnode, but if there is, ignore it.
  1781. //
  1782. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1783. return(STATUS_DATA_NOT_ACCEPTED);
  1784. }
  1785. }
  1786. else
  1787. {
  1788. //
  1789. // It is a RELEASE REQUEST - so decide if the name should be removed
  1790. // from the remote or local table
  1791. //
  1792. // check for errors Bug# 125651 (NBT_MINIMUM_REGREQUEST == 68)
  1793. //
  1794. // Check for valid PDU size:
  1795. // lNumBytes >= 12 + [1+lNameSize] + 22(sizeof(tGENERALRR))
  1796. // Check for Overflow error during comparisons with local names:
  1797. // lNumBytes >= 12 + [1+32(EncodedNetBios name)+Scope(==1 if NULL Scope)] + 22
  1798. //
  1799. if ((lNumBytes < ((NBT_MINIMUM_REGREQUEST-33) + lNameSize)) ||
  1800. (lNumBytes < (NBT_MINIMUM_REGREQUEST + (NbtConfig.ScopeLength-1))))
  1801. {
  1802. // IF_DBG(NBT_DEBUG_NAMESRV)
  1803. KdPrint (("Nbt.NameReleaseFromNet[2]: WARNING!!! Rejecting Request -- lNumBytes<%d> < <%d>\n",
  1804. lNumBytes, (NBT_MINIMUM_REGREQUEST + (NbtConfig.ScopeLength-1))));
  1805. return(STATUS_DATA_NOT_ACCEPTED);
  1806. }
  1807. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1808. // check the REMOTE hash table for the name...
  1809. //
  1810. status = FindInHashTable(NbtConfig.pRemoteHashTbl,
  1811. pName,
  1812. pScope,
  1813. &pNameAddr);
  1814. bLocalTable = FALSE;
  1815. if (!NT_SUCCESS(status))
  1816. {
  1817. //
  1818. // check the LOCAL name table for the name since the name server
  1819. // could be doing the equivalent of a name conflict demand
  1820. //
  1821. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  1822. pName,
  1823. pScope,
  1824. &pNameAddr);
  1825. bLocalTable = TRUE;
  1826. }
  1827. if (NT_SUCCESS(status))
  1828. {
  1829. // check if the address being released corresponds to the one in
  1830. // the table - if not then ignore the release request - since someone
  1831. // else presumably tried to get the name, was refused and now is
  1832. // sending a name release request.
  1833. //
  1834. pRemainder = (tGENERALRR *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  1835. if (pNameAddr->IpAddress != (ULONG)ntohl(pRemainder->IpAddress))
  1836. {
  1837. status = STATUS_UNSUCCESSFUL;
  1838. }
  1839. }
  1840. else
  1841. {
  1842. //
  1843. // This name is neither in our local or remote hash table, so don't
  1844. // process any further!
  1845. // Bug#: 144944
  1846. //
  1847. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1848. return(STATUS_DATA_NOT_ACCEPTED);
  1849. }
  1850. if (NT_SUCCESS(status))
  1851. {
  1852. //
  1853. // Don't remove group names, since a single group member
  1854. // releasing the name does not matter. Group names time
  1855. // out of the Remote table.
  1856. //
  1857. if (pNameAddr->NameTypeState & NAMETYPE_UNIQUE)
  1858. {
  1859. switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
  1860. {
  1861. case STATE_RESOLVING:
  1862. //
  1863. // stop any timer that may be going
  1864. //
  1865. CHECK_PTR(pNameAddr);
  1866. //
  1867. // Local table means that it is a name registration
  1868. // and we must avoid calling CompleteClientReq
  1869. //
  1870. if (pTimer = pNameAddr->pTimer)
  1871. {
  1872. COMPLETIONCLIENT pClientCompletion;
  1873. PVOID pContext;
  1874. pNameAddr->pTimer = NULL;
  1875. status = StopTimer(pTimer,&pClientCompletion,&pContext);
  1876. // this will complete the irp(s) back to the clients
  1877. if (pClientCompletion)
  1878. {
  1879. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1880. if (bLocalTable)
  1881. {
  1882. (*pClientCompletion) (pContext,STATUS_DUPLICATE_NAME);
  1883. }
  1884. else
  1885. {
  1886. CompleteClientReq (pClientCompletion, pContext, STATUS_TIMEOUT);
  1887. }
  1888. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1889. }
  1890. }
  1891. break;
  1892. case STATE_RESOLVED:
  1893. // dereference the name if it is in the remote table,
  1894. // this should change the state to RELEASED. For the
  1895. // local table just change the state to CONFLICT, since
  1896. // the local client still thinks it has the name open,
  1897. // however in the conflict state the name cannot be use
  1898. // to place new sessions and this node will not respond
  1899. // to name queries for the name.
  1900. //
  1901. if (!bLocalTable)
  1902. {
  1903. //
  1904. // if this is a pre-loaded name, just leave it alone
  1905. //
  1906. if (!(pNameAddr->NameTypeState & PRELOADED))
  1907. {
  1908. //
  1909. // if someone is still using the name, do not
  1910. // dereference it, since that would leave the
  1911. // ref count at 1, and allow RemoteHashTimeout
  1912. // code to remove it before the client using
  1913. // the name is done with it. Once the client is
  1914. // done with it (i.e. a connect request), they
  1915. // will deref it , setting the ref count to 1 and
  1916. // it will be suitable for reuse.
  1917. //
  1918. if (pNameAddr->RefCount > 1)
  1919. {
  1920. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  1921. pNameAddr->NameTypeState |= STATE_RELEASED;
  1922. }
  1923. else
  1924. {
  1925. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  1926. }
  1927. }
  1928. }
  1929. else
  1930. {
  1931. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  1932. pNameAddr->NameTypeState |= STATE_CONFLICT;
  1933. pNameAddr->ConflictMask |= pDeviceContext->AdapterMask;
  1934. NbtLogEvent (EVENT_NBT_NAME_RELEASE, SrcAddress, 0x103);
  1935. }
  1936. break;
  1937. default:
  1938. break;
  1939. }
  1940. }
  1941. //
  1942. // tell WINS that the name released ok
  1943. //
  1944. Rcode = 0;
  1945. }
  1946. else
  1947. {
  1948. Rcode = NAME_ERROR;
  1949. }
  1950. //
  1951. // Only respond if not a broadcast...
  1952. //
  1953. if (!(OpCodeFlags & FL_BROADCAST))
  1954. {
  1955. status = UdpSendResponse(
  1956. lNameSize,
  1957. pNameHdr,
  1958. NULL,
  1959. (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
  1960. pDeviceContext,
  1961. Rcode,
  1962. eNAME_RELEASE,
  1963. OldIrq1);
  1964. }
  1965. else
  1966. {
  1967. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1968. }
  1969. } // end of Release Request processing
  1970. return (STATUS_DATA_NOT_ACCEPTED);
  1971. }
  1972. //----------------------------------------------------------------------------
  1973. NTSTATUS
  1974. WackFromNet(
  1975. IN tDEVICECONTEXT *pDeviceContext,
  1976. IN PVOID pSrcAddress,
  1977. IN tNAMEHDR UNALIGNED *pNameHdr,
  1978. IN LONG lNumBytes
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. This routine handles Wait Acks from the name server. It finds the corresponding
  1983. name service transaction and changes the timeout of that transaction according
  1984. to the TTL field in the WACK.
  1985. Arguments:
  1986. Return Value:
  1987. NTSTATUS - success or not - failure means no response to net
  1988. --*/
  1989. {
  1990. NTSTATUS status;
  1991. ULONG lNameSize;
  1992. CHAR pName[NETBIOS_NAME_SIZE];
  1993. PUCHAR pScope;
  1994. tNAMEADDR *pNameAddr;
  1995. CTELockHandle OldIrq1;
  1996. ULONG Ttl;
  1997. tTIMERQENTRY *pTimerEntry;
  1998. //
  1999. // check the pdu size for errors
  2000. //
  2001. if (lNumBytes < (NBT_MINIMUM_WACK + NbtConfig.ScopeLength -1))
  2002. {
  2003. KdPrint(("Nbt:WACK TOO short = %X\n",lNumBytes));
  2004. return(STATUS_DATA_NOT_ACCEPTED);
  2005. }
  2006. // get the name out of the network pdu and pass to routine to check
  2007. status = ConvertToAscii(
  2008. (PCHAR)&pNameHdr->NameRR,
  2009. lNumBytes - FIELD_OFFSET(tNAMEHDR,NameRR),
  2010. pName,
  2011. &pScope,
  2012. &lNameSize);
  2013. if (!NT_SUCCESS(status))
  2014. {
  2015. // IF_DBG(NBT_DEBUG_NAMESRV)
  2016. KdPrint (("Nbt.WackFromNet: WARNING!!! Rejecting Request -- ConvertToAscii FAILed\n"));
  2017. return(STATUS_DATA_NOT_ACCEPTED);
  2018. }
  2019. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  2020. #ifdef VXD
  2021. if ( FindContextDirect( pNameHdr->TransactId ) != NULL )
  2022. {
  2023. status = STATUS_SUCCESS;
  2024. }
  2025. else
  2026. {
  2027. #endif // VXD
  2028. status = FindInHashTable(NbtConfig.pLocalHashTbl,
  2029. pName,
  2030. pScope,
  2031. &pNameAddr);
  2032. #ifdef VXD
  2033. }
  2034. #endif // VXD
  2035. if (NT_SUCCESS(status))
  2036. {
  2037. Ttl = *(ULONG UNALIGNED *)((ULONG_PTR)&pNameHdr->NameRR.NetBiosName[0]
  2038. + lNameSize
  2039. + FIELD_OFFSET(tQUERYRESP,Ttl) );
  2040. Ttl = ntohl(Ttl);
  2041. if (pTimerEntry = pNameAddr->pTimer)
  2042. {
  2043. // convert seconds to milliseconds and put into the DeltaTime
  2044. // field so that when the next timeout occurs it changes the timer
  2045. // value to this new one. Depending on how many timeouts are left
  2046. // this could cause the client to wait several times the WACK timeout
  2047. // value. For example a Name query nominally has two retries, so if
  2048. // the WACK returns before the first retry then the total time waited
  2049. // will be 2*Ttl. This is not a problem since the real reason for
  2050. // the timeout is to prevent waiting forever for a dead name server.
  2051. // If the server returns a WACK it is not dead and the chances are
  2052. // that it will return a response before the timeout anyway.
  2053. //
  2054. // The timeout routine checks if TIMER_RETIMED is set and restarts
  2055. // the timeout without any processing if that is true ( and clears
  2056. // the flag too).
  2057. //
  2058. Ttl *= 1000;
  2059. if (Ttl > pTimerEntry->DeltaTime)
  2060. {
  2061. pTimerEntry->DeltaTime = Ttl;
  2062. pTimerEntry->Flags |= TIMER_RETIMED;
  2063. }
  2064. }
  2065. }
  2066. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  2067. return(STATUS_DATA_NOT_ACCEPTED);
  2068. }
  2069. //----------------------------------------------------------------------------
  2070. VOID
  2071. SetupRefreshTtl(
  2072. IN tNAMEHDR UNALIGNED *pNameHdr,
  2073. IN tNAMEADDR *pNameAddr,
  2074. IN LONG lNameSize
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. This routine handles name refresh timeouts. It looks at the Ttl in the
  2079. registration response and determines if the Node's refresh timeout should
  2080. be lengthened or shortened. To do this both the Ttl and the name associated
  2081. with the Ttl are kept in the Config structure. If the Ttl becomes longer
  2082. for the shortest names Ttl, then all the names use the longer value.
  2083. Arguments:
  2084. Return Value:
  2085. NTSTATUS - success or not - failure means no response to net
  2086. --*/
  2087. {
  2088. NTSTATUS status;
  2089. ULONG Ttl;
  2090. tTIMERQENTRY *pTimerQEntry;
  2091. // the Ttl in the pdu is in seconds. We need to convert it to milliseconds
  2092. // to use for our timer. This limits the timeout value to about 50 days
  2093. // ( 2**32 / 3600/24/1000 - milliseconds converted to days.)
  2094. //
  2095. Ttl = *(ULONG UNALIGNED *) ((PUCHAR)&pNameHdr->NameRR.NetBiosName[0]
  2096. + lNameSize
  2097. + FIELD_OFFSET(tQUERYRESP,Ttl));
  2098. Ttl = ntohl(Ttl);
  2099. // the Ttl value may overflow the value we can store in Milliseconds,
  2100. // check for this case, and if it happens, use the longest timeout possible
  2101. // that still runs refresh, - i.e. NBT_MAXIMUM_TTL disables refresh
  2102. // altogether, so use NBT_MAXIMUM_TTL-1).
  2103. if (Ttl >= 0xFFFFFFFF/1000)
  2104. {
  2105. Ttl = NBT_MAXIMUM_TTL - 1;
  2106. }
  2107. else
  2108. {
  2109. Ttl *= 1000; // convert to milliseconds
  2110. }
  2111. // a zero Ttl means infinite, so set time the largest timeout
  2112. //
  2113. if (Ttl == 0)
  2114. {
  2115. Ttl = NBT_MAXIMUM_TTL; // set very large number which turns off refreshes
  2116. }
  2117. else
  2118. if (Ttl < NBT_MINIMUM_TTL)
  2119. {
  2120. Ttl = NBT_MINIMUM_TTL;
  2121. }
  2122. // Set the Ttl for the name record
  2123. //
  2124. pNameAddr->Ttl = Ttl;
  2125. //
  2126. // decide what to do about the existing timer....
  2127. // If the new timeout is shorter, then cancel the
  2128. // current timeout and start another one.
  2129. //
  2130. if (Ttl < NbtConfig.MinimumTtl)
  2131. {
  2132. IF_DBG(NBT_DEBUG_NAMESRV)
  2133. KdPrint(("Nbt:Shortening Refresh Ttl from %d to %d\n",
  2134. NbtConfig.MinimumTtl, Ttl));
  2135. NbtConfig.MinimumTtl = (ULONG)Ttl;
  2136. //
  2137. // don't allow the stop timer routine to call the completion routine
  2138. // for the timer.
  2139. //
  2140. if (pTimerQEntry = NbtConfig.pRefreshTimer)
  2141. {
  2142. CHECK_PTR(pTimerQEntry);
  2143. pTimerQEntry->TimeoutRoutine = NULL;
  2144. status = StopTimer(pTimerQEntry,NULL,NULL);
  2145. }
  2146. // keep the timeout for checking refreshes to about 10 minutes
  2147. // max. (MAX_REFRESH_CHECK_INTERVAL). If the refresh interval
  2148. // is less than 80 minutes then always use a refresh divisor of
  2149. // 8 - this allows the initial default ttl of 16 minutes to result
  2150. // in retries every 2 minutes.
  2151. //
  2152. NbtConfig.RefreshDivisor = NbtConfig.MinimumTtl/MAX_REFRESH_CHECK_INTERVAL;
  2153. if (NbtConfig.RefreshDivisor < REFRESH_DIVISOR)
  2154. {
  2155. NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
  2156. }
  2157. //
  2158. // start the timer
  2159. //
  2160. status = StartTimer(RefreshTimeout,
  2161. Ttl/NbtConfig.RefreshDivisor,
  2162. NULL, // context value
  2163. NULL, // context2 value
  2164. NULL,
  2165. NULL,
  2166. NULL, // This Timer is a global timer
  2167. &NbtConfig.pRefreshTimer,
  2168. 0,
  2169. TRUE);
  2170. #if DBG
  2171. if (!NT_SUCCESS(status))
  2172. {
  2173. KdPrint(("Nbt:Failed to start a new timer for refresh\n"));
  2174. }
  2175. #endif
  2176. }
  2177. else
  2178. if (Ttl > NbtConfig.MinimumTtl)
  2179. {
  2180. tHASHTABLE *pHashTable;
  2181. LONG i;
  2182. PLIST_ENTRY pHead,pEntry;
  2183. // PUT this code back in again, since it is possible that the name
  2184. // server could miss registering a name due to being busy and if we
  2185. // lengthen the timeout here then that name will not get into wins for
  2186. // a very long time.
  2187. // the shortest Ttl got longer, check if there is another shortest
  2188. // Ttl by scanning the local name table.
  2189. //
  2190. pHashTable = NbtConfig.pLocalHashTbl;
  2191. for (i=0;i < pHashTable->lNumBuckets ;i++ )
  2192. {
  2193. pHead = &pHashTable->Bucket[i];
  2194. pEntry = pHead->Flink;
  2195. while (pEntry != pHead)
  2196. {
  2197. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  2198. //
  2199. // Find a valid name with a lower TTL if possible
  2200. //
  2201. if ((pNameAddr->Name[0] != '*') &&
  2202. ((pNameAddr->NameTypeState & STATE_RESOLVED)) &&
  2203. (pNameAddr->Ttl < (ULONG)Ttl) &&
  2204. (!IsBrowserName(pNameAddr->Name)) &&
  2205. (!(pNameAddr->NameTypeState & NAMETYPE_QUICK)))
  2206. {
  2207. if (pNameAddr->Ttl >= NBT_MINIMUM_TTL)
  2208. {
  2209. NbtConfig.MinimumTtl = pNameAddr->Ttl;
  2210. }
  2211. return;
  2212. }
  2213. pEntry = pEntry->Flink;
  2214. }
  2215. }
  2216. //
  2217. // if we get to here then there is no shorter ttl, so use the new
  2218. // ttl received from the WINS as the ttl. The next time the refresh
  2219. // timer expires it will restart with this new ttl
  2220. //
  2221. IF_DBG(NBT_DEBUG_NAMESRV)
  2222. KdPrint(("Nbt:Lengthening Refresh Ttl from %d to %d\n",
  2223. NbtConfig.MinimumTtl, Ttl));
  2224. NbtConfig.MinimumTtl = Ttl;
  2225. // keep the timeout for checking refreshes to about 10 minutes
  2226. // max. (MAX_REFRESH_CHECK_INTERVAL). If the refresh interval
  2227. // is less than 80 minutes then always use a refresh divisor of
  2228. // 8 - this allows the initial default ttl of 16 minutes to result
  2229. // in retries every 2 minutes.
  2230. //
  2231. NbtConfig.RefreshDivisor = NbtConfig.MinimumTtl/MAX_REFRESH_CHECK_INTERVAL;
  2232. if (NbtConfig.RefreshDivisor < REFRESH_DIVISOR)
  2233. {
  2234. NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
  2235. }
  2236. }
  2237. }
  2238. //----------------------------------------------------------------------------
  2239. NTSTATUS
  2240. DecodeNodeStatusResponse(
  2241. IN tNAMEHDR UNALIGNED *pNameHdr,
  2242. IN ULONG Length,
  2243. IN PUCHAR pName,
  2244. IN ULONG lNameSize,
  2245. IN tIPADDRESS SrcIpAddress
  2246. )
  2247. /*++
  2248. Routine Description:
  2249. This routine handles putting the node status response pdu into the clients
  2250. MDL.
  2251. Arguments:
  2252. Return Value:
  2253. none
  2254. --*/
  2255. {
  2256. NTSTATUS status;
  2257. PLIST_ENTRY pHead;
  2258. PLIST_ENTRY pEntry;
  2259. PLIST_ENTRY pNext;
  2260. tNODESTATUS UNALIGNED *pNodeStatus;
  2261. CTELockHandle OldIrq;
  2262. CTELockHandle OldIrq2;
  2263. tDGRAM_SEND_TRACKING *pTracker;
  2264. tTIMERQENTRY *pTimer;
  2265. COMPLETIONCLIENT pClientCompletion;
  2266. PVOID pClientContext;
  2267. BOOL MatchFound=FALSE;
  2268. tIPADDRESS IpAddress;
  2269. PVOID pBuffer;
  2270. // first find the originating request in the NodeStatus list
  2271. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  2272. CTESpinLock(&NbtConfig,OldIrq);
  2273. pEntry = pHead = &NbtConfig.NodeStatusHead;
  2274. while ((pEntry = pEntry->Flink) != pHead)
  2275. {
  2276. pTracker = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,Linkage);
  2277. ASSERT (NBT_VERIFY_HANDLE (pTracker, NBT_VERIFY_TRACKER));
  2278. ASSERT (pTracker->TrackerType == NBT_TRACKER_SEND_NODE_STATUS);
  2279. if (!(pTimer = pTracker->pTimer))
  2280. {
  2281. continue;
  2282. }
  2283. MatchFound = FALSE;
  2284. //
  2285. // find who sent the request originally
  2286. //
  2287. if (pTracker->Flags & REMOTE_ADAPTER_STAT_FLAG)
  2288. {
  2289. IpAddress = Nbt_inet_addr(pTracker->pNameAddr->Name, REMOTE_ADAPTER_STAT_FLAG);
  2290. }
  2291. else
  2292. {
  2293. IpAddress = 0;
  2294. }
  2295. if ((CTEMemEqu(pName,pTracker->pNameAddr->Name,NETBIOS_NAME_SIZE)) ||
  2296. ((IpAddress==SrcIpAddress)&&(IpAddress!=0)))
  2297. {
  2298. //
  2299. // if we directed node status request to an ipaddr without knowing
  2300. // its netbios name, then name is stored as "* ".
  2301. //
  2302. if ((pName[0] == '*') && (IpAddress == 0) && (pTracker->pNameAddr->pIpAddrsList))
  2303. {
  2304. int i=0;
  2305. //
  2306. // SrcIpAddress may not match the ipaddr to which we sent if
  2307. // remote host is multihomed: so search whole list of all
  2308. // ipaddrs for that host
  2309. //
  2310. ASSERT(pTracker->pNameAddr->pIpAddrsList);
  2311. while(pTracker->pNameAddr->pIpAddrsList[i])
  2312. {
  2313. if (pTracker->pNameAddr->pIpAddrsList[i++] == SrcIpAddress)
  2314. {
  2315. MatchFound = TRUE;
  2316. break;
  2317. }
  2318. }
  2319. }
  2320. else
  2321. {
  2322. MatchFound = TRUE;
  2323. }
  2324. }
  2325. if (MatchFound)
  2326. {
  2327. RemoveEntryList(pEntry);
  2328. InitializeListHead (&pTracker->Linkage); // in case the Timeout routine is running
  2329. // this is the amount of data left, that we do not want to go
  2330. // beyond, otherwise the system will bugcheck
  2331. //
  2332. Length -= FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize;
  2333. pNodeStatus = (tNODESTATUS *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  2334. CTESpinFree(&NbtConfig,OldIrq);
  2335. status = StopTimer(pTimer,&pClientCompletion,&pClientContext);
  2336. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2337. if (pClientCompletion)
  2338. {
  2339. tDGRAM_SEND_TRACKING *pClientTracker = (tDGRAM_SEND_TRACKING *) pClientContext;
  2340. pClientTracker->RemoteIpAddress = SrcIpAddress;
  2341. pClientTracker->pNodeStatus = pNodeStatus;
  2342. pClientTracker->NodeStatusLen = Length;
  2343. (*pClientCompletion) (pClientContext, STATUS_SUCCESS);
  2344. }
  2345. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  2346. CTESpinLock(&NbtConfig,OldIrq);
  2347. break;
  2348. }
  2349. }
  2350. CTESpinFree(&NbtConfig,OldIrq);
  2351. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2352. return(STATUS_UNSUCCESSFUL);
  2353. }
  2354. //----------------------------------------------------------------------------
  2355. typedef enum _dest_type {
  2356. IP_ADDR,
  2357. DNS,
  2358. NETBIOS
  2359. } DEST_TYPE;
  2360. DEST_TYPE
  2361. GetDestType(
  2362. IN tDGRAM_SEND_TRACKING *pClientTracker
  2363. )
  2364. /*++
  2365. Routine Description:
  2366. Classifies name passed in as an IP addr/Netbios name/Dns name
  2367. Arguments:
  2368. Return Value:
  2369. DEST_TYPE
  2370. --*/
  2371. {
  2372. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2373. KdPrint(("Nbt.GetDestType: Name=<%16.16s:%x>\n",
  2374. pClientTracker->pDestName, pClientTracker->pDestName[15]));
  2375. if (Nbt_inet_addr(pClientTracker->pDestName, 0))
  2376. {
  2377. return IP_ADDR;
  2378. }
  2379. else if (pClientTracker->RemoteNameLength > NETBIOS_NAME_SIZE)
  2380. {
  2381. return DNS;
  2382. }
  2383. else
  2384. {
  2385. return NETBIOS;
  2386. }
  2387. }
  2388. //----------------------------------------------------------------------------
  2389. VOID
  2390. ExtractServerNameCompletion(
  2391. IN tDGRAM_SEND_TRACKING *pClientTracker,
  2392. IN NTSTATUS status
  2393. )
  2394. /*++
  2395. Routine Description:
  2396. This Routine searches for the server name (name ending with 0x20) from the
  2397. list of names returned by node status response, and adds that name to the
  2398. remote hash table.
  2399. Arguments:
  2400. pNodeStatus Node status response from the remote host
  2401. pClientContext Tracker for the seutp phase
  2402. IpAddress Ip address of the node that just responded
  2403. Return Value:
  2404. none
  2405. --*/
  2406. {
  2407. ULONG i;
  2408. UCHAR NodeFlags, NameExtension;
  2409. PCHAR pName;
  2410. PCHAR pBestName = NULL;
  2411. tSESSIONREQ *pSessionReq;
  2412. PUCHAR pCopyTo;
  2413. DEST_TYPE DestType;
  2414. ULONG TrackerFlags;
  2415. COMPLETIONCLIENT pClientCompletion;
  2416. PVOID pClientContext;
  2417. tNODESTATUS UNALIGNED *pNodeStatus = pClientTracker->pNodeStatus;
  2418. tIPADDRESS IpAddress = pClientTracker->RemoteIpAddress;
  2419. BOOL bForce20NameLookup = FALSE;
  2420. tDEVICECONTEXT *pDeviceContext = NULL;
  2421. ASSERT (NBT_VERIFY_HANDLE (pClientTracker, NBT_VERIFY_TRACKER));
  2422. if (STATUS_SUCCESS == status)
  2423. {
  2424. status = STATUS_REMOTE_NOT_LISTENING;
  2425. DestType = GetDestType(pClientTracker);
  2426. TrackerFlags = pClientTracker->Flags;
  2427. NameExtension = pClientTracker->pDestName[NETBIOS_NAME_SIZE-1];
  2428. //
  2429. // If the not a Netbios name, and the 16th character is ASCII,
  2430. // then look for the Server name
  2431. //
  2432. if ((DestType != NETBIOS) &&
  2433. (NameExtension > 0x20 ) &&
  2434. (NameExtension < 0x7f ))
  2435. {
  2436. NameExtension = SPECIAL_SERVER_SUFFIX;
  2437. }
  2438. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2439. KdPrint(("ExtractSrvName: DestType: %d\n", DestType));
  2440. bForce20NameLookup = FALSE;
  2441. again:
  2442. if (bForce20NameLookup) {
  2443. DestType = DNS;
  2444. NameExtension = 0x20;
  2445. }
  2446. for(i =0; i<pNodeStatus->NumNames; i++)
  2447. {
  2448. pName = &pNodeStatus->NodeName[i].Name[0];
  2449. NodeFlags = pNodeStatus->NodeName[i].Flags;
  2450. //
  2451. // make sure it's a unique name (for connects only, for dgram sends, group names are fine)
  2452. // and is not in conflict or released
  2453. //
  2454. if ((NodeFlags & (NODE_NAME_CONFLICT | NODE_NAME_RELEASED)) ||
  2455. !(((TrackerFlags & SESSION_SETUP_FLAG) && !(NodeFlags & GROUP_STATUS)) ||
  2456. (TrackerFlags & (DGRAM_SEND_FLAG | REMOTE_ADAPTER_STAT_FLAG))))
  2457. {
  2458. continue;
  2459. }
  2460. if ((DestType == IP_ADDR) || (DestType == DNS))
  2461. {
  2462. if (pName[NETBIOS_NAME_SIZE-1] != NameExtension)
  2463. {
  2464. continue;
  2465. }
  2466. //
  2467. // For IP addresses and DNS names, we map the 0x20 name to the corresp 0x0 name
  2468. // for datagram sends.
  2469. //
  2470. if (pClientTracker->Flags & DGRAM_SEND_FLAG)
  2471. {
  2472. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2473. KdPrint(("ExtractServerName: Mapping 0x20 name to 0x0\n"));
  2474. pName[NETBIOS_NAME_SIZE-1] = 0x0;
  2475. }
  2476. }
  2477. //
  2478. // For Netbios names (resolved via DNS), we match the 16th byte exactly
  2479. //
  2480. else if (pName[NETBIOS_NAME_SIZE-1] != pClientTracker->pDestName[NETBIOS_NAME_SIZE-1])
  2481. {
  2482. continue;
  2483. }
  2484. pDeviceContext = GetDeviceFromInterface(ntohl(IpAddress), TRUE);
  2485. status = STATUS_SUCCESS;
  2486. break; // found the name: done with the for loop
  2487. }
  2488. if (!NT_SUCCESS(status) && !bForce20NameLookup &&
  2489. NameExtension > 0x20 && NameExtension < 0x7f &&
  2490. pClientTracker->RemoteNameLength == NETBIOS_NAME_SIZE) {
  2491. // It might be a FQDN that is exactly the same size as NETBIOS_NAME_SIZE
  2492. // better check again with that assumption.
  2493. bForce20NameLookup = TRUE;
  2494. goto again;
  2495. }
  2496. if (NT_SUCCESS(status))
  2497. {
  2498. //
  2499. // fix up the connection tracker to point to the right name, now
  2500. // that we know the server name to connect to
  2501. //
  2502. //
  2503. // The FIND_NAME_FLAG was set to indicate that this is not a session setup attempt so
  2504. // we can avoid the call to ConvertToHalfAscii.
  2505. //
  2506. if (!(pClientTracker->Flags & FIND_NAME_FLAG))
  2507. {
  2508. if (pClientTracker->Flags & SESSION_SETUP_FLAG)
  2509. {
  2510. CTEMemCopy(pClientTracker->SendBuffer.pBuffer,pName,NETBIOS_NAME_SIZE);
  2511. CTEMemCopy(pClientTracker->pConnEle->RemoteName,pName,NETBIOS_NAME_SIZE);
  2512. #ifdef VXD
  2513. CTEMemCopy(&pClientTracker->pClientIrp->ncb_callname[0],pName,NETBIOS_NAME_SIZE);
  2514. #endif // VXD
  2515. pSessionReq = pClientTracker->SendBuffer.pDgramHdr;
  2516. //
  2517. // overwrite the Dest HalfAscii name in the Session Pdu with the correct name
  2518. //
  2519. pCopyTo = ConvertToHalfAscii((PCHAR)&pSessionReq->CalledName.NameLength,
  2520. pName,
  2521. NbtConfig.pScope,
  2522. NbtConfig.ScopeLength);
  2523. }
  2524. else if (pClientTracker->Flags & DGRAM_SEND_FLAG)
  2525. {
  2526. PCHAR pCopyTo;
  2527. tDGRAMHDR *pDgramHdr;
  2528. //
  2529. // Overwrite the dest name, so SendDgramContinue can find the name
  2530. // in the caches.
  2531. //
  2532. CTEMemCopy(pClientTracker->pDestName,pName,NETBIOS_NAME_SIZE);
  2533. //
  2534. // Copy over the actual dest name in half-ascii
  2535. // This is immediately after the SourceName; so offset the
  2536. // dest by the length of the src name.
  2537. //
  2538. pDgramHdr = pClientTracker->SendBuffer.pDgramHdr;
  2539. pCopyTo = (PVOID)&pDgramHdr->SrcName.NameLength;
  2540. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2541. KdPrint(("pCopyTo:%lx\n", pCopyTo));
  2542. pCopyTo += 1 + // Length field
  2543. 2 * NETBIOS_NAME_SIZE + // actual name in half-ascii
  2544. NbtConfig.ScopeLength; // length of scope
  2545. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2546. KdPrint(("pCopyTo:%lx\n", pCopyTo));
  2547. ConvertToHalfAscii (pCopyTo, pName, NbtConfig.pScope, NbtConfig.ScopeLength);
  2548. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2549. KdPrint(("Copied the remote name for dgram sends\n"));
  2550. }
  2551. }
  2552. else
  2553. {
  2554. KdPrint(("ExtractServerName: Find name going on\n"));
  2555. }
  2556. //
  2557. // Add this server name to the remote hashtable
  2558. // if Nameaddr can't be added, it means an entry already exists
  2559. // Get that entry and update its ipaddr.
  2560. //
  2561. LockAndAddToHashTable (NbtConfig.pRemoteHashTbl,
  2562. pName,
  2563. NbtConfig.pScope,
  2564. IpAddress,
  2565. NBT_UNIQUE,
  2566. NULL,
  2567. NULL,
  2568. pDeviceContext,
  2569. (USHORT) ((TrackerFlags & NBT_DNS_SERVER) ?
  2570. NAME_RESOLVED_BY_DNS | NAME_RESOLVED_BY_ADAP_STAT:
  2571. NAME_RESOLVED_BY_ADAP_STAT));
  2572. }
  2573. }
  2574. if (pDeviceContext)
  2575. {
  2576. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_OUT_FROM_IP, FALSE);
  2577. }
  2578. pClientCompletion = pClientTracker->CompletionRoutine;
  2579. pClientContext = pClientTracker; // Use this same tracker as the context
  2580. CompleteClientReq(pClientCompletion, pClientContext, status);
  2581. }
  2582. //----------------------------------------------------------------------------
  2583. VOID
  2584. CopyNodeStatusResponseCompletion(
  2585. IN tDGRAM_SEND_TRACKING *pClientTracker,
  2586. IN NTSTATUS status
  2587. )
  2588. /*++
  2589. Routine Description:
  2590. This Routine copies data received from the net node status response to
  2591. the client's irp. It is called from inbound.c when a node status response
  2592. comes in from the wire.
  2593. Arguments:
  2594. pIrp - a ptr to an IRP
  2595. Return Value:
  2596. none
  2597. --*/
  2598. {
  2599. ULONG NumNames;
  2600. ULONG i;
  2601. PADAPTER_STATUS pAdapterStatus = NULL;
  2602. PNAME_BUFFER pNameBuffer;
  2603. ULONG BuffSize;
  2604. ULONG AccumLength;
  2605. PUCHAR pAscii;
  2606. UCHAR Flags;
  2607. ULONG DataLength;
  2608. ULONG DestSize ;
  2609. tSTATISTICS UNALIGNED *pStatistics;
  2610. ULONG SrcIpAddress;
  2611. ULONG TotalLength;
  2612. tNODESTATUS *pNodeStat;
  2613. COMPLETIONCLIENT pClientCompletion;
  2614. PIRP pIrp;
  2615. tNAMEADDR *pNameAddr;
  2616. CTELockHandle OldIrq, OldIrq1;
  2617. CHECK_PTR(pClientTracker);
  2618. SrcIpAddress = pClientTracker->RemoteIpAddress;
  2619. TotalLength = pClientTracker->NodeStatusLen;
  2620. pClientTracker->NodeStatusLen = 0;
  2621. pNodeStat = (tNODESTATUS *) pClientTracker->pNodeStatus;
  2622. pClientTracker->pNodeStatus = NULL;
  2623. pIrp = pClientTracker->ClientContext;
  2624. ASSERT (NBT_VERIFY_HANDLE (pClientTracker, NBT_VERIFY_TRACKER));
  2625. ASSERT (pClientTracker->TrackerType == NBT_TRACKER_ADAPTER_STATUS);
  2626. pClientTracker->pDeviceContext = NULL; // Can be set below if we need add the name to the cache
  2627. if (STATUS_SUCCESS == status)
  2628. {
  2629. //
  2630. // Bug# 125629:
  2631. // We have already verified in QueryFromNet (just before calling
  2632. // DecodeNodeStatusResponse) that the NodeStatus structure is
  2633. // large enough to cover the NumNames field + it has the number of
  2634. // names specified in that field
  2635. //
  2636. NumNames = pNodeStat->NumNames;
  2637. BuffSize = sizeof(ADAPTER_STATUS) + NumNames*sizeof(NAME_BUFFER);
  2638. // sanity check that we are not allocating more than 64K for this stuff
  2639. if (BuffSize > 0xFFFF)
  2640. {
  2641. status = STATUS_UNSUCCESSFUL;
  2642. goto ExitRoutine;
  2643. }
  2644. pAdapterStatus = NbtAllocMem((USHORT)BuffSize,NBT_TAG('9'));
  2645. if (!pAdapterStatus)
  2646. {
  2647. status = STATUS_INSUFFICIENT_RESOURCES;
  2648. goto ExitRoutine;
  2649. }
  2650. // Fill out the adapter status structure with zeros first
  2651. CTEZeroMemory((PVOID)pAdapterStatus,BuffSize);
  2652. // get the source MAC address from the statistics portion of the pdu
  2653. //
  2654. if (TotalLength >= (NumNames*sizeof(tNODENAME) + sizeof(tSTATISTICS)))
  2655. {
  2656. pStatistics = (tSTATISTICS UNALIGNED *)((PUCHAR)&pNodeStat->NodeName[0] + NumNames*sizeof(tNODENAME));
  2657. CTEMemCopy(&pAdapterStatus->adapter_address[0], &pStatistics->UnitId[0], sizeof(tMAC_ADDRESS));
  2658. }
  2659. pAdapterStatus->rev_major = 0x03;
  2660. pAdapterStatus->adapter_type = 0xFE; // pretend it is an ethernet adapter
  2661. //
  2662. // get the ptr to the statistics field if there is one in the pdu
  2663. //
  2664. AccumLength = NumNames * sizeof(tNODENAME) +
  2665. FIELD_OFFSET(tNODESTATUS, NodeName) + sizeof(USHORT) +
  2666. FIELD_OFFSET( tSTATISTICS, SessionDataPacketSize ) ;
  2667. if (AccumLength <= TotalLength)
  2668. {
  2669. //
  2670. // there is a whole statistics portion to the adapter status command,
  2671. // so we can get the session pdu size out of it.
  2672. //
  2673. pAdapterStatus->max_sess = ntohs((USHORT)*((PUCHAR)pNodeStat + AccumLength - sizeof(USHORT)));
  2674. }
  2675. // get the address of the name buffer at the end of the adapter status
  2676. // structure so we can copy the names into this area.
  2677. pNameBuffer = (NAME_BUFFER *) ((ULONG_PTR)pAdapterStatus + sizeof(ADAPTER_STATUS));
  2678. // set the AccumLength to the start of the node name array in the buffer
  2679. // so we can count through the buffer and be sure not to run off the end
  2680. //
  2681. AccumLength = FIELD_OFFSET(tNODESTATUS, NodeName);
  2682. //
  2683. // We need to determine the outgoing Device for the remote machine, in
  2684. // case we need to add any names below.
  2685. //
  2686. pClientTracker->pDeviceContext = GetDeviceFromInterface (htonl(SrcIpAddress), TRUE);
  2687. for(i =0; i< NumNames; i++)
  2688. {
  2689. AccumLength += sizeof(tNODENAME);
  2690. if (AccumLength > TotalLength)
  2691. {
  2692. //
  2693. // The remote buffer is incomplete, what else can we do?
  2694. //
  2695. status = STATUS_UNSUCCESSFUL;
  2696. goto ExitCleanup;
  2697. }
  2698. pAdapterStatus->name_count++ ;
  2699. pAscii = (PCHAR)&pNodeStat->NodeName[i].Name[0];
  2700. Flags = pNodeStat->NodeName[i].Flags;
  2701. pNameBuffer->name_flags = (Flags & GROUP_STATUS) ? GROUP_NAME : UNIQUE_NAME;
  2702. //
  2703. // map the name states
  2704. //
  2705. if (Flags & NODE_NAME_CONFLICT)
  2706. {
  2707. if (Flags & NODE_NAME_RELEASED)
  2708. pNameBuffer->name_flags |= DUPLICATE_DEREG;
  2709. else
  2710. pNameBuffer->name_flags |= DUPLICATE;
  2711. }
  2712. else if (Flags & NODE_NAME_RELEASED)
  2713. {
  2714. pNameBuffer->name_flags |= DEREGISTERED;
  2715. }
  2716. else
  2717. {
  2718. pNameBuffer->name_flags |= REGISTERED;
  2719. }
  2720. pNameBuffer->name_num = (UCHAR)i+1;
  2721. CTEMemCopy(pNameBuffer->name,pAscii,NETBIOS_NAME_SIZE);
  2722. //
  2723. // If the name is the 0x20 name, see if we can add it to the remote hashtable
  2724. // (only if the name is not already there)!
  2725. //
  2726. if ((pAscii[NETBIOS_NAME_SIZE-1] == 0x20) &&
  2727. ((Flags & (NODE_NAME_CONFLICT | NODE_NAME_RELEASED)) == 0))
  2728. {
  2729. NbtAddEntryToRemoteHashTable (pClientTracker->pDeviceContext,
  2730. NAME_RESOLVED_BY_ADAP_STAT,
  2731. pAscii,
  2732. SrcIpAddress,
  2733. NbtConfig.RemoteTimeoutCount*60, // from minutes to secs
  2734. UNIQUE_STATUS);
  2735. }
  2736. pNameBuffer++;
  2737. }
  2738. //
  2739. // Reduce the name count if we can't fit the buffer
  2740. //
  2741. #ifdef VXD
  2742. DestSize = ((NCB*)pIrp)->ncb_length ;
  2743. #else
  2744. DestSize = MmGetMdlByteCount( pIrp->MdlAddress ) ;
  2745. #endif
  2746. CHECK_PTR(pAdapterStatus);
  2747. if ( BuffSize > DestSize )
  2748. {
  2749. if ( DestSize < sizeof( ADAPTER_STATUS ))
  2750. {
  2751. pAdapterStatus->name_count = 0 ;
  2752. }
  2753. else
  2754. {
  2755. pAdapterStatus->name_count = (WORD) (DestSize- sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER) ;
  2756. }
  2757. }
  2758. //
  2759. // Copy the built adapter status structure
  2760. //
  2761. #ifdef VXD
  2762. if ( BuffSize > DestSize )
  2763. {
  2764. status = STATUS_BUFFER_OVERFLOW ;
  2765. BuffSize = DestSize ;
  2766. }
  2767. else
  2768. {
  2769. status = STATUS_SUCCESS ;
  2770. }
  2771. CTEMemCopy(((NCB*)pIrp)->ncb_buffer, pAdapterStatus, BuffSize);
  2772. ((NCB*)pIrp)->ncb_length = (WORD) BuffSize; // Set here to be compatible with NT
  2773. #else
  2774. status = TdiCopyBufferToMdl (pAdapterStatus, 0, BuffSize, pIrp->MdlAddress, 0, &DataLength);
  2775. pIrp->IoStatus.Information = DataLength;
  2776. pIrp->IoStatus.Status = status;
  2777. #endif
  2778. }
  2779. ExitCleanup:
  2780. if (pAdapterStatus)
  2781. {
  2782. CTEMemFree((PVOID)pAdapterStatus);
  2783. }
  2784. ExitRoutine:
  2785. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2786. //
  2787. // the tracker block was unlinked in DecodeNodeStatusResponse,
  2788. // and its header was freed when the send completed, so just relink
  2789. // it here - this deref should do the relink.
  2790. //
  2791. if (pIrp)
  2792. {
  2793. if (status == STATUS_SUCCESS ||
  2794. status == STATUS_BUFFER_OVERFLOW ) // Only partial data copied
  2795. {
  2796. // -1 means the receive length is already set in the irp
  2797. CTEIoComplete(pIrp,status,0xFFFFFFFF);
  2798. }
  2799. else
  2800. {
  2801. //
  2802. // failed to get the adapter status, so
  2803. // return failure status to the client.
  2804. //
  2805. CTEIoComplete(pIrp,STATUS_IO_TIMEOUT,0);
  2806. }
  2807. }
  2808. if (pClientTracker->pDeviceContext)
  2809. {
  2810. NBT_DEREFERENCE_DEVICE (pClientTracker->pDeviceContext, REF_DEV_OUT_FROM_IP, TRUE);
  2811. }
  2812. NBT_DEREFERENCE_TRACKER (pClientTracker, TRUE);
  2813. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2814. }
  2815. //----------------------------------------------------------------------------
  2816. NTSTATUS
  2817. SendNodeStatusResponse(
  2818. IN tNAMEHDR UNALIGNED *pInNameHdr,
  2819. IN ULONG Length,
  2820. IN PUCHAR pName,
  2821. IN ULONG lNameSize,
  2822. IN tIPADDRESS SrcIpAddress,
  2823. IN USHORT SrcPort,
  2824. IN tDEVICECONTEXT *pDeviceContext
  2825. )
  2826. /*++
  2827. Routine Description:
  2828. This routine handles putting the node status response pdu into the clients
  2829. MDL.
  2830. Arguments:
  2831. Return Value:
  2832. none
  2833. --*/
  2834. {
  2835. NTSTATUS status;
  2836. PUCHAR pScope;
  2837. PUCHAR pInScope;
  2838. ULONG Position;
  2839. ULONG CountNames;
  2840. ULONG BuffSize;
  2841. tNODESTATUS UNALIGNED *pNodeStatus;
  2842. tNAMEHDR *pNameHdr;
  2843. CTELockHandle OldIrq2;
  2844. ULONG i;
  2845. PLIST_ENTRY pHead;
  2846. PLIST_ENTRY pEntry;
  2847. tADDRESSELE *pAddressEle;
  2848. tNAMEADDR *pNameAddr;
  2849. tDGRAM_SEND_TRACKING *pTracker;
  2850. ULONG InScopeLength;
  2851. tSTATISTICS UNALIGNED *pStatistics;
  2852. tNODENAME UNALIGNED *pNode;
  2853. CTEULONGLONG AdapterMask;
  2854. ULONG Len;
  2855. if (Length > sizeof(tNAMEHDR) + lNameSize - 1 + sizeof(ULONG))
  2856. {
  2857. return(STATUS_DATA_NOT_ACCEPTED);
  2858. }
  2859. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  2860. // verify that the requesting node is in the same scope as this node, so
  2861. // get a ptr to the scope, which starts 16*2 (32) bytes into the
  2862. // netbios name in the pdu.
  2863. //
  2864. pInScope = (PUCHAR)&pInNameHdr->NameRR.NetBiosName[(NETBIOS_NAME_SIZE <<1)];
  2865. pScope = NbtConfig.pScope;
  2866. Position = sizeof(tNAMEHDR) - sizeof(tNETBIOS_NAME) +1 + (NETBIOS_NAME_SIZE <<1);
  2867. // check the scope length
  2868. InScopeLength = Length - Position - sizeof(ULONG);
  2869. if (InScopeLength != NbtConfig.ScopeLength)
  2870. {
  2871. status = STATUS_DATA_NOT_ACCEPTED;
  2872. goto ErrorExit;
  2873. }
  2874. // compare scopes for equality and avoid running off the end of the pdu
  2875. //
  2876. i= 0;
  2877. while (i < NbtConfig.ScopeLength)
  2878. {
  2879. if (*pInScope != *pScope)
  2880. {
  2881. status = STATUS_DATA_NOT_ACCEPTED;
  2882. goto ErrorExit;
  2883. }
  2884. i++;
  2885. pInScope++;
  2886. pScope++;
  2887. }
  2888. // get the count of names, excluding '*...' which we do not send...
  2889. //
  2890. CountNames = CountLocalNames(&NbtConfig);
  2891. IF_DBG(NBT_DEBUG_NAMESRV)
  2892. KdPrint(("Nbt:Node Status Response, with %d names\n",CountNames));
  2893. // this is only a byte field, so only allow up to 255 names.
  2894. if (CountNames > 255)
  2895. {
  2896. CountNames = 255;
  2897. }
  2898. // Allocate Memory for the adapter status
  2899. // - ULONG for the Nbstat and IN that are part of Length. CountNames-1
  2900. // because there is one name in sizeof(tNODESTATUS) already
  2901. //
  2902. BuffSize = Length + sizeof(tNODESTATUS) - sizeof(ULONG) + (CountNames-1)*sizeof(tNODENAME)
  2903. + sizeof(tSTATISTICS);
  2904. pNameHdr = (tNAMEHDR *)NbtAllocMem((USHORT)BuffSize,NBT_TAG('A'));
  2905. if (!pNameHdr)
  2906. {
  2907. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  2908. return(STATUS_INSUFFICIENT_RESOURCES);
  2909. }
  2910. // copy the request to the response and change a few bits around
  2911. //
  2912. CTEMemCopy((PVOID)pNameHdr,(PVOID)pInNameHdr,Length);
  2913. pNameHdr->OpCodeFlags = OP_RESPONSE | FL_AUTHORITY;
  2914. pNameHdr->QdCount = 0;
  2915. pNameHdr->AnCount = 1;
  2916. pNodeStatus = (tNODESTATUS UNALIGNED *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  2917. pNodeStatus->Ttl = 0;
  2918. pNode = (tNODENAME UNALIGNED *)&pNodeStatus->NodeName[0];
  2919. AdapterMask = pDeviceContext->AdapterMask;
  2920. i = 0;
  2921. pEntry = pHead = &NbtConfig.AddressHead;
  2922. while ((pEntry = pEntry->Flink) != pHead)
  2923. {
  2924. pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
  2925. pNameAddr = pAddressEle->pNameAddr;
  2926. pNode->Flags = (pAddressEle->NameType == NBT_UNIQUE) ? UNIQUE_STATUS : GROUP_STATUS;
  2927. // all names have this one set
  2928. //
  2929. pNode->Flags |= NODE_NAME_ACTIVE;
  2930. switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
  2931. {
  2932. default:
  2933. case STATE_RESOLVED:
  2934. break;
  2935. case STATE_CONFLICT:
  2936. pNode->Flags |= NODE_NAME_CONFLICT;
  2937. break;
  2938. case STATE_RELEASED:
  2939. pNode->Flags |= NODE_NAME_RELEASED;
  2940. break;
  2941. case STATE_RESOLVING:
  2942. // don't count these names.
  2943. continue;
  2944. }
  2945. switch (NodeType & NODE_MASK)
  2946. {
  2947. case BNODE:
  2948. pNode->Flags |= STATUS_BNODE;
  2949. break;
  2950. case MSNODE:
  2951. case MNODE:
  2952. pNode->Flags |= STATUS_MNODE;
  2953. break;
  2954. case PNODE:
  2955. pNode->Flags |= STATUS_PNODE;
  2956. }
  2957. CHECK_PTR(pNode);
  2958. // Copy the name in the pdu
  2959. CTEMemCopy((PVOID)&pNode->Name[0], (PVOID)pNameAddr->Name, NETBIOS_NAME_SIZE);
  2960. pNode->Resrved = 0;
  2961. // check for the permanent name...and add it too
  2962. //
  2963. if (pNameAddr->NameTypeState & NAMETYPE_QUICK)
  2964. {
  2965. //
  2966. // the permanent name is added as a Quick Add in the name table
  2967. // do not put the permanent name into the response
  2968. //
  2969. continue;
  2970. }
  2971. else if ((pNameAddr->Name[0] == '*') ||
  2972. (pNameAddr->NameTypeState & STATE_RESOLVING) ||
  2973. (!(pNameAddr->AdapterMask & AdapterMask)))
  2974. {
  2975. //
  2976. // do not put the broadcast name into the response, since neither
  2977. // NBF or WFW NBT puts it there.
  2978. // Also, to not respond with resolving names, or names that are
  2979. // not registered on this adapter (multihomed case)
  2980. //
  2981. continue;
  2982. }
  2983. i++;
  2984. pNode++;
  2985. CHECK_PTR(pNode);
  2986. if (i >= CountNames)
  2987. {
  2988. break;
  2989. }
  2990. }
  2991. CHECK_PTR(pNameHdr);
  2992. CHECK_PTR(pNodeStatus);
  2993. //
  2994. // set the count of names in the response packet
  2995. //
  2996. pNodeStatus->NumNames = (UCHAR)i;
  2997. Len = i*sizeof(tNODENAME) + 1 + sizeof(tSTATISTICS); //+1 for NumNames Byte
  2998. pNodeStatus->Length = (USHORT)htons(Len);
  2999. // fill in some of the statistics fields which occur after the name table
  3000. // in the PDU
  3001. //
  3002. pStatistics = (tSTATISTICS UNALIGNED *)((PUCHAR)&pNodeStatus->NodeName[0] + i*sizeof(tNODENAME));
  3003. CTEZeroMemory((PVOID)pStatistics,sizeof(tSTATISTICS));
  3004. //
  3005. // put the MAC address in the response
  3006. //
  3007. CTEMemCopy(&pStatistics->UnitId[0], &pDeviceContext->MacAddress.Address[0], sizeof(tMAC_ADDRESS));
  3008. //
  3009. // Now send the node status message
  3010. //
  3011. status = GetTracker(&pTracker, NBT_TRACKER_NODE_STATUS_RESPONSE);
  3012. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3013. if (!NT_SUCCESS(status))
  3014. {
  3015. CTEMemFree((PVOID)pNameHdr);
  3016. }
  3017. else
  3018. {
  3019. CHECK_PTR(pTracker);
  3020. pTracker->SendBuffer.HdrLength = BuffSize;
  3021. pTracker->SendBuffer.pDgramHdr = (PVOID)pNameHdr;
  3022. pTracker->SendBuffer.pBuffer = NULL;
  3023. pTracker->SendBuffer.Length = 0;
  3024. pTracker->pDeviceContext = pDeviceContext;
  3025. status = UdpSendDatagram(pTracker,
  3026. SrcIpAddress,
  3027. QueryRespDone, // this routine frees memory and puts the tracker back
  3028. pTracker,
  3029. SrcPort, // NBT_NAMESERVICE_UDP_PORT 31343 - reply to port request came on...
  3030. NBT_NAME_SERVICE);
  3031. }
  3032. return(status);
  3033. ErrorExit:
  3034. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  3035. return(status);
  3036. }
  3037. //----------------------------------------------------------------------------
  3038. NTSTATUS
  3039. UpdateNameState(
  3040. IN tADDSTRUCT UNALIGNED *pAddrStruct,
  3041. IN tNAMEADDR *pNameAddr,
  3042. IN ULONG Len,
  3043. #ifdef MULTIPLE_WINS
  3044. IN PULONG pContextFlags,
  3045. #endif
  3046. IN tDEVICECONTEXT *pDeviceContext,
  3047. IN BOOLEAN NameServerIsSrc,
  3048. IN tDGRAM_SEND_TRACKING *pTracker,
  3049. IN CTELockHandle OldIrq1
  3050. )
  3051. /*++
  3052. Routine Description:
  3053. This routine handles putting a list of names into the hash table when
  3054. a response is received that contains one or more than one ip address.
  3055. Arguments:
  3056. Return Value:
  3057. none
  3058. --*/
  3059. {
  3060. ULONG i, CountAddrs;
  3061. tIPADDRESS *pIpList;
  3062. ULONG ExtraNames;
  3063. NTSTATUS status = STATUS_SUCCESS;
  3064. CTELockHandle OldIrq;
  3065. USHORT NameAddFlags = (NameServerIsSrc ? NAME_RESOLVED_BY_WINS : NAME_RESOLVED_BY_BCAST);
  3066. //
  3067. // put all of the addresses into a list that is pointed to by the pNameAddr record
  3068. // Terminate it with -1 (0 means a broadcast address)
  3069. //
  3070. ASSERT(pNameAddr->pIpAddrsList == NULL);
  3071. CountAddrs = Len / tADDSTRUCT_SIZE;
  3072. if ((CountAddrs > NBT_MAX_INTERNET_GROUP_ADDRS)|| // probably a badly formated packet (max value=1000)
  3073. (CountAddrs*tADDSTRUCT_SIZE != Len) ||
  3074. (!(pNameAddr->pIpAddrsList = NbtAllocMem(sizeof(tIPADDRESS)*(1+CountAddrs),NBT_TAG('8')))))
  3075. {
  3076. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  3077. return (STATUS_UNSUCCESSFUL);
  3078. }
  3079. /*
  3080. * Replace broadcast address -1 (0xffffffff) with 0 because -1 is reserved as terminator
  3081. */
  3082. for (i = 0; i < CountAddrs; i++) {
  3083. pNameAddr->pIpAddrsList[i] = (pAddrStruct[i].IpAddr == (tIPADDRESS)(-1))? 0: htonl(pAddrStruct[i].IpAddr);
  3084. }
  3085. pNameAddr->pIpAddrsList[CountAddrs] = (tIPADDRESS)(-1);
  3086. // a pos. response to a previous query, so change the state in the
  3087. // hash table to RESOLVED
  3088. CHECK_PTR(pNameAddr);
  3089. if (pNameAddr->NameTypeState & STATE_RESOLVING)
  3090. {
  3091. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  3092. pNameAddr->NameTypeState |= STATE_RESOLVED;
  3093. // check if a group name...
  3094. //
  3095. if (ntohs(pAddrStruct->NbFlags) & FL_GROUP)
  3096. {
  3097. pNameAddr->NameTypeState &= ~NAME_TYPE_MASK;
  3098. // It is difficult to differentiate nameserver responses from
  3099. // single node responses, when a single ip address is returned.
  3100. // It could be the name server returning an Inet Group with one
  3101. // entry or another node simply responding with its address.
  3102. //
  3103. // If the response is just a single broadcast address, we store
  3104. // it as type NAMETYPE_GROUP, otherwise we should store it as
  3105. // NAMETYPE_INET_GROUP -- we should remove the check for NameServer
  3106. // since it does not always work for muti-homed, or cluster Wins servers
  3107. //
  3108. // WINS puts -1 to say it's a groupname
  3109. //
  3110. if ((CountAddrs == 1) &&
  3111. (pAddrStruct->IpAddr == (ULONG)-1))
  3112. {
  3113. // using zero here tells the UdpSendDatagramCode to
  3114. // send to the subnet broadcast address when talking to
  3115. // that address.
  3116. //
  3117. // For Bnodes store the Address of the node that responded
  3118. // to the group name query, since we do allow sessions to
  3119. // group names for BNODES since they can resolve the name to
  3120. // and IP address, whereas other nodes cannot.
  3121. //
  3122. // store the ipaddr regardless of nodetype. We don't know if this info will be
  3123. // used to setup a session or send a datagram. We do check NameTypeState
  3124. // while setting up session, so no need to filter out NodeType info here.
  3125. ASSERT(pAddrStruct->IpAddr == (ULONG)-1);
  3126. pNameAddr->IpAddress = 0;
  3127. pNameAddr->NameTypeState |= NAMETYPE_GROUP;
  3128. }
  3129. else
  3130. {
  3131. NameAddFlags |= NAME_ADD_INET_GROUP;
  3132. pNameAddr->NameTypeState |= NAMETYPE_INET_GROUP;
  3133. }
  3134. }
  3135. else
  3136. {
  3137. if (CountAddrs > 1)
  3138. {
  3139. tIPADDRESS IpAddress;
  3140. NBT_WORK_ITEM_CONTEXT *pContext;
  3141. // the name query response contains several ip addresses for
  3142. // a multihomed host, so pick an address that matches one of
  3143. // our subnet masks
  3144. //
  3145. // Do the old thing for datagram sends/name queries.
  3146. //
  3147. #ifndef VXD
  3148. if ((NbtConfig.TryAllAddr) &&
  3149. (pTracker) &&
  3150. (pTracker->Flags & SESSION_SETUP_FLAG))
  3151. {
  3152. if (NT_SUCCESS(status = ChooseBestIpAddress(pAddrStruct,
  3153. Len,
  3154. pDeviceContext,
  3155. pTracker,
  3156. &IpAddress,
  3157. TRUE)))
  3158. {
  3159. //
  3160. // At this point, pTracker->IPList contains the sorted list of destination
  3161. // IP addresses. Submit this list to the lmhsvc service to ping each and
  3162. // return which is reachable.
  3163. //
  3164. pContext = (NBT_WORK_ITEM_CONTEXT *) NbtAllocMem (sizeof(NBT_WORK_ITEM_CONTEXT), NBT_TAG('H'));
  3165. if (pContext)
  3166. {
  3167. pContext->pTracker = NULL; // no query tracker
  3168. pContext->pClientContext = pTracker; // the client tracker
  3169. pContext->ClientCompletion = SessionSetupContinue;
  3170. pContext->pDeviceContext = pTracker->pDeviceContext;
  3171. StartLmHostTimer(pContext, TRUE);
  3172. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  3173. IF_DBG(NBT_DEBUG_NAMESRV)
  3174. KdPrint(("Nbt.UpdateNameState: Kicking off CheckAddr : %lx\n", pAddrStruct));
  3175. status = NbtProcessLmhSvcRequest(pContext, NBT_PING_IP_ADDRS);
  3176. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  3177. if (NT_SUCCESS(status))
  3178. {
  3179. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE); // PendingQ name
  3180. ASSERT (status == STATUS_PENDING);
  3181. return (status); // shd be STATUS_PENDING
  3182. }
  3183. CTEFreeMem (pContext);
  3184. KdPrint(("Nbt.UpdateNameState: ERROR %lx -- NbtProcessLmhSvcRequest\n", status));
  3185. }
  3186. else
  3187. {
  3188. KdPrint(("Nbt.UpdateNameState: ERROR -- Couldn't alloc mem for pContext\n"));
  3189. }
  3190. //
  3191. // We failed above, but we still the addresses that were returned, so
  3192. // just pick up the first Ip address!
  3193. //
  3194. pNameAddr->IpAddress = IpAddress;
  3195. status = STATUS_SUCCESS;
  3196. }
  3197. else
  3198. {
  3199. KdPrint(("Nbt.UpdateNameState: ERROR -- ChooseBestIpAddress returned %lx\n", status));
  3200. }
  3201. }
  3202. else
  3203. #endif
  3204. {
  3205. IF_DBG(NBT_DEBUG_NAMESRV)
  3206. KdPrint(("Nbt:Choosing best IP addr...\n"));
  3207. if (NT_SUCCESS (status = ChooseBestIpAddress(pAddrStruct,Len,pDeviceContext,
  3208. pTracker, &IpAddress, FALSE)))
  3209. {
  3210. pNameAddr->IpAddress = IpAddress;
  3211. }
  3212. #ifdef MULTIPLE_WINS
  3213. #ifdef VXD
  3214. //
  3215. // This is a hack to make VNBT work for multi-homed machines since
  3216. // currently we don't ping the addresses as in the case of NT above
  3217. // to find a good address
  3218. //
  3219. // Reset the ContextFlags so that we re-query the same server to make
  3220. // sure we try all the addresses
  3221. //
  3222. if (pTracker)
  3223. {
  3224. *pContextFlags = pTracker->ResolutionContextFlags;
  3225. }
  3226. #endif // VXD
  3227. #endif // MULTIPLE_WINS
  3228. }
  3229. }
  3230. else
  3231. {
  3232. // it is already set to a unique address...since that is the default
  3233. // when the name is queried originally.
  3234. pNameAddr->IpAddress = ntohl(pAddrStruct->IpAddr);
  3235. }
  3236. }
  3237. }
  3238. if (NT_SUCCESS(status))
  3239. {
  3240. AddToHashTable (NbtConfig.pRemoteHashTbl,
  3241. pNameAddr->Name,
  3242. NbtConfig.pScope,
  3243. pNameAddr->IpAddress,
  3244. 0,
  3245. pNameAddr,
  3246. NULL,
  3247. pDeviceContext,
  3248. NameAddFlags);
  3249. }
  3250. else
  3251. {
  3252. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  3253. }
  3254. return(STATUS_SUCCESS);
  3255. }
  3256. //----------------------------------------------------------------------------
  3257. ULONG
  3258. MakeList(
  3259. IN tDEVICECONTEXT *pDeviceContext,
  3260. IN ULONG CountAddrs,
  3261. IN tADDSTRUCT UNALIGNED *pAddrStruct,
  3262. IN tIPADDRESS *pAddrArray,
  3263. IN ULONG SizeOfAddrArray,
  3264. IN BOOLEAN IsSubnetMatch
  3265. )
  3266. /*++
  3267. Routine Description:
  3268. This routine gets a list of ip addresses that match the network number
  3269. This can either be the subnet number or the network number depending
  3270. on the boolean IsSubnetMatch
  3271. Arguments:
  3272. Return Value:
  3273. none
  3274. --*/
  3275. {
  3276. PLIST_ENTRY pHead;
  3277. PLIST_ENTRY pEntry;
  3278. tDEVICECONTEXT *pTmpDevContext;
  3279. ULONG MatchAddrs = 0;
  3280. tADDSTRUCT UNALIGNED *pAddrs;
  3281. ULONG i;
  3282. ULONG IpAddr, NetworkNumber, NetworkNumberInIpAddr;
  3283. UCHAR IpAddrByte;
  3284. pHead = &NbtConfig.DeviceContexts;
  3285. pEntry = pHead;
  3286. while ((pEntry = pEntry->Flink) != pHead)
  3287. {
  3288. pAddrs = pAddrStruct;
  3289. pTmpDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  3290. //
  3291. // DeviceContext is non-null, if a check has to be made on a specific
  3292. // DeviceContext. Otherwise it's null (i.e. check all DeviceContexts)
  3293. //
  3294. if (pDeviceContext)
  3295. {
  3296. if (pTmpDevContext != pDeviceContext)
  3297. {
  3298. continue;
  3299. }
  3300. }
  3301. //
  3302. // Check whether the Caller requested a Subnet or Network number match,
  3303. // and if they are 0 for this Device, go to the next device
  3304. //
  3305. if (IsSubnetMatch)
  3306. {
  3307. NetworkNumber = pTmpDevContext->SubnetMask & pTmpDevContext->IpAddress;
  3308. }
  3309. else
  3310. {
  3311. NetworkNumber = pTmpDevContext->NetMask;
  3312. }
  3313. //
  3314. // If the Subnet Mask or Network Mask is 0, then there is no use
  3315. // proceeding further since the Device is probably not up
  3316. //
  3317. if (!NetworkNumber)
  3318. {
  3319. continue;
  3320. }
  3321. // extract the ipaddress from each address structure
  3322. for ( i = 0 ; i < CountAddrs; i++ )
  3323. {
  3324. NetworkNumberInIpAddr = IpAddr = ntohl(pAddrs->IpAddr);
  3325. if (IsSubnetMatch)
  3326. {
  3327. if (((pTmpDevContext->SubnetMask & IpAddr) == NetworkNumber) &&
  3328. (MatchAddrs < SizeOfAddrArray/sizeof(ULONG)))
  3329. {
  3330. // put the ipaddress into a list incase multiple match
  3331. // and we want to select one randomly
  3332. //
  3333. pAddrArray[MatchAddrs++] = IpAddr;
  3334. }
  3335. pAddrs++;
  3336. }
  3337. else
  3338. {
  3339. IpAddrByte = ((PUCHAR)&IpAddr)[3];
  3340. if ((IpAddrByte & 0x80) == 0)
  3341. {
  3342. // class A address - one byte netid
  3343. NetworkNumberInIpAddr &= 0xFF000000;
  3344. }
  3345. else if ((IpAddrByte & 0xC0) ==0x80)
  3346. {
  3347. // class B address - two byte netid
  3348. NetworkNumberInIpAddr &= 0xFFFF0000;
  3349. }
  3350. else if ((IpAddrByte & 0xE0) ==0xC0)
  3351. {
  3352. // class C address - three byte netid
  3353. NetworkNumberInIpAddr &= 0xFFFFFF00;
  3354. }
  3355. if ((NetworkNumberInIpAddr == NetworkNumber) &&
  3356. (MatchAddrs < SizeOfAddrArray/sizeof(ULONG)))
  3357. {
  3358. // put the ipaddress into a list incase multiple match
  3359. // and we want to select one randomly
  3360. //
  3361. pAddrArray[MatchAddrs++] = IpAddr;
  3362. }
  3363. pAddrs++;
  3364. }
  3365. }
  3366. }
  3367. return(MatchAddrs);
  3368. }
  3369. //----------------------------------------------------------------------------
  3370. NTSTATUS
  3371. ChooseBestIpAddress(
  3372. IN tADDSTRUCT UNALIGNED *pAddrStruct,
  3373. IN ULONG Len,
  3374. IN tDEVICECONTEXT *pDeviceContext,
  3375. OUT tDGRAM_SEND_TRACKING *pTracker,
  3376. OUT tIPADDRESS *pIpAddress,
  3377. IN BOOLEAN fReturnAddrList
  3378. )
  3379. /*++
  3380. Routine Description:
  3381. This routine gets a list of ip addresses and attempts to pick one of them
  3382. as the best address. This occurs when WINS returns a list of addresses
  3383. for a multihomed host and we want want the one that is on a subnet
  3384. corresponding to one of the network cards. Failing to match on
  3385. subnet mask, results in a random selection from the addresses.
  3386. Arguments:
  3387. Return Value:
  3388. none
  3389. --*/
  3390. {
  3391. ULONG CountAddrs, NextAddr, MatchAddrs = 0;
  3392. ULONG i, j, Random;
  3393. tIPADDRESS MatchAddrArray[60];
  3394. tADDSTRUCT temp;
  3395. CTESystemTime TimeValue;
  3396. // one or more addresses were returned,
  3397. // so pick one that is best
  3398. //
  3399. CountAddrs = Len / tADDSTRUCT_SIZE;
  3400. if (CountAddrs*tADDSTRUCT_SIZE == Len)
  3401. {
  3402. //
  3403. // Randomize all of the addresses!
  3404. //
  3405. for (i=CountAddrs-1; i>0; i--)
  3406. {
  3407. CTEQuerySystemTime(TimeValue);
  3408. Random = RandomizeFromTime(TimeValue, (i+1));
  3409. ASSERT (Random < CountAddrs);
  3410. if (Random != i)
  3411. {
  3412. //
  3413. // Exchange the address at Random with i!
  3414. //
  3415. temp = pAddrStruct[Random];
  3416. pAddrStruct[Random] = pAddrStruct[i];
  3417. pAddrStruct[i] = temp;
  3418. }
  3419. }
  3420. //
  3421. // First check if any addresses are on the same subnet as this
  3422. // devicecontext.
  3423. //
  3424. MatchAddrs = MakeList(pDeviceContext,
  3425. CountAddrs,
  3426. pAddrStruct,
  3427. MatchAddrArray,
  3428. sizeof(MatchAddrArray),
  3429. TRUE);
  3430. //
  3431. // if none of the ipaddrs is on the same subnet as this DeviceContext,
  3432. // try other DeviceContexts
  3433. //
  3434. if (!MatchAddrs)
  3435. {
  3436. MatchAddrs = MakeList(NULL,
  3437. CountAddrs,
  3438. pAddrStruct,
  3439. MatchAddrArray,
  3440. sizeof(MatchAddrArray),
  3441. TRUE);
  3442. }
  3443. // if none of the addresses match the subnet address of any of the
  3444. // DeviceContexts, then go through the same checks looking for matches
  3445. // that have the same network number as the Device this name was resolved on.
  3446. // Bug # 212432
  3447. //
  3448. if (!MatchAddrs)
  3449. {
  3450. MatchAddrs = MakeList(pDeviceContext,
  3451. CountAddrs,
  3452. pAddrStruct,
  3453. MatchAddrArray,
  3454. sizeof(MatchAddrArray),
  3455. FALSE);
  3456. }
  3457. //
  3458. // if none of the addresses match the subnet address of any of the
  3459. // DeviceContexts, then go through the same check looking for matches
  3460. // that have the same network number for any connected device.
  3461. //
  3462. if (!MatchAddrs)
  3463. {
  3464. MatchAddrs = MakeList(NULL,
  3465. CountAddrs,
  3466. pAddrStruct,
  3467. MatchAddrArray,
  3468. sizeof(MatchAddrArray),
  3469. FALSE);
  3470. }
  3471. }
  3472. else
  3473. {
  3474. // the pdu length is not an even multiple of the tADDSTRUCT data
  3475. // structure
  3476. return(STATUS_UNSUCCESSFUL);
  3477. }
  3478. //
  3479. // We had already randomized the list earlier, so now just pick up
  3480. // the first address for the IpAddress value!
  3481. //
  3482. if (MatchAddrs)
  3483. {
  3484. *pIpAddress = MatchAddrArray[0];
  3485. }
  3486. else // No match
  3487. {
  3488. *pIpAddress = htonl(pAddrStruct[0].IpAddr);
  3489. }
  3490. //
  3491. // See if the Caller requested only 1 IP address
  3492. //
  3493. if (!fReturnAddrList)
  3494. {
  3495. return (STATUS_SUCCESS);
  3496. }
  3497. //
  3498. // Move all addresses which matched any of the Subnets or Network numbers
  3499. // to the top of the list (if no matches, then we will copy the whole list as is)
  3500. //
  3501. if (MatchAddrs)
  3502. {
  3503. //
  3504. // Sort the IP addr list on basis of best IP addr. in MatchAddrArray
  3505. //
  3506. // NOTE: this is not a strictly sorted list (the actual sort might be too expensive),
  3507. // instead we take all the addresses that match the subnet mask (say) and
  3508. // clump the remaining ones in the same group. This way we ensure that whatever
  3509. // we chose as the best address is still given preference as compared to the
  3510. // other addresses.
  3511. //
  3512. //
  3513. // NextAddr is the index of the next Address in AddrStruct which can be switched
  3514. //
  3515. NextAddr = 0;
  3516. for (i=0; i<MatchAddrs; i++) // for each address which matched the Net/Subnet masks
  3517. {
  3518. //
  3519. // SWAP(pAddrStruct[NextAddr], pAddrStruct[Index(MatchAddrArray[i])]);
  3520. //
  3521. for (j=NextAddr; j<CountAddrs; j++)
  3522. {
  3523. if (pAddrStruct[j].IpAddr == (ULONG)ntohl(MatchAddrArray[i]))
  3524. {
  3525. if (j != NextAddr) // Swap if indices are different
  3526. {
  3527. IF_DBG(NBT_DEBUG_NAMESRV)
  3528. KdPrint(("Nbt.ChooseBestIpAddress: Swap Address[%d]=<%x> <=> Address[%d]=<%x>\n",
  3529. NextAddr, pAddrStruct[NextAddr].IpAddr, j, pAddrStruct[j].IpAddr));
  3530. temp = pAddrStruct[NextAddr];
  3531. pAddrStruct[NextAddr] = pAddrStruct[j];
  3532. pAddrStruct[j] = temp;
  3533. }
  3534. NextAddr++; // Fill in next Address
  3535. break;
  3536. }
  3537. }
  3538. if (NextAddr >= CountAddrs)
  3539. {
  3540. break;
  3541. }
  3542. }
  3543. }
  3544. //
  3545. // We will have to return the list of IP addresses in the
  3546. // Tracker's IpList field, so ensure that pTracker is valid
  3547. //
  3548. if (!pTracker)
  3549. {
  3550. return(STATUS_UNSUCCESSFUL);
  3551. }
  3552. //
  3553. // Now copy all the addresses into the Tracker's IP List
  3554. //
  3555. pTracker->IpList = NbtAllocMem(sizeof(ULONG)*(1+CountAddrs),NBT_TAG('8'));
  3556. if (!pTracker->IpList)
  3557. {
  3558. return (STATUS_INSUFFICIENT_RESOURCES);
  3559. }
  3560. for (j=0; j<CountAddrs; j++)
  3561. {
  3562. IF_DBG(NBT_DEBUG_NAMESRV)
  3563. KdPrint(("Nbt.ChooseBestIpAddress: pAddrStruct[%d/%d]: %lx\n", (j+1), CountAddrs, pAddrStruct[j].IpAddr));
  3564. pTracker->IpList[j] = pAddrStruct[j].IpAddr;
  3565. }
  3566. pTracker->IpList[CountAddrs] = 0;
  3567. pTracker->NumAddrs = CountAddrs;
  3568. return (STATUS_SUCCESS);
  3569. }
  3570. //----------------------------------------------------------------------------
  3571. #ifdef MULTIPLE_WINS
  3572. BOOLEAN
  3573. IsNameServerForDevice(
  3574. IN ULONG SrcAddress,
  3575. IN tDEVICECONTEXT *pDevContext
  3576. )
  3577. /*++
  3578. Routine Description:
  3579. This function checks the src address against this adapter's name server
  3580. addresses to see if it is a name server.
  3581. Arguments:
  3582. Return Value:
  3583. BOOLEAN - TRUE or FALSE
  3584. --*/
  3585. {
  3586. int i;
  3587. if ((pDevContext->lNameServerAddress == SrcAddress) ||
  3588. (pDevContext->lBackupServer == SrcAddress))
  3589. {
  3590. return(TRUE);
  3591. }
  3592. for (i=0; i < pDevContext->lNumOtherServers; i++)
  3593. {
  3594. if (pDevContext->lOtherServers[i] == SrcAddress)
  3595. {
  3596. return (TRUE);
  3597. }
  3598. }
  3599. return (FALSE);
  3600. }
  3601. //----------------------------------------------------------------------------
  3602. #endif
  3603. BOOLEAN
  3604. SrcIsNameServer(
  3605. IN ULONG SrcAddress,
  3606. IN USHORT SrcPort
  3607. )
  3608. /*++
  3609. Routine Description:
  3610. This function checks the src address against all adapters' name server
  3611. address to see if it came from a name server.
  3612. Arguments:
  3613. Return Value:
  3614. NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
  3615. --*/
  3616. {
  3617. PLIST_ENTRY pHead;
  3618. PLIST_ENTRY pEntry;
  3619. tDEVICECONTEXT *pDevContext;
  3620. pHead = &NbtConfig.DeviceContexts;
  3621. pEntry = pHead->Flink;
  3622. if (SrcPort == NbtConfig.NameServerPort)
  3623. {
  3624. while (pEntry != pHead)
  3625. {
  3626. pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  3627. #ifdef MULTIPLE_WINS
  3628. if (IsNameServerForDevice(SrcAddress, pDevContext))
  3629. #else
  3630. if ((pDevContext->lNameServerAddress == SrcAddress) ||
  3631. (pDevContext->lBackupServer == SrcAddress))
  3632. #endif
  3633. {
  3634. return(TRUE);
  3635. }
  3636. pEntry = pEntry->Flink;
  3637. }
  3638. }
  3639. #ifndef VXD
  3640. //
  3641. // If wins is on this machine the above SrcIsNameServer
  3642. // check may not be sufficient since this machine is
  3643. // the name server and that check checks the nameservers
  3644. // used for name queries. If WINS is on this machine it
  3645. // could have sent from any local adapter's IP address
  3646. //
  3647. if (pWinsInfo)
  3648. {
  3649. return(SrcIsUs(SrcAddress));
  3650. }
  3651. #endif
  3652. return(FALSE);
  3653. }
  3654. //----------------------------------------------------------------------------
  3655. BOOLEAN
  3656. SrcIsUs(
  3657. IN ULONG SrcAddress
  3658. )
  3659. /*++
  3660. Routine Description:
  3661. This function checks the src address against all adapters'Ip addresses
  3662. address to see if it came from this node.
  3663. Arguments:
  3664. Return Value:
  3665. NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
  3666. --*/
  3667. {
  3668. PLIST_ENTRY pHead;
  3669. PLIST_ENTRY pEntry;
  3670. tDEVICECONTEXT *pDevContext;
  3671. pHead = &NbtConfig.DeviceContexts;
  3672. pEntry = pHead->Flink;
  3673. while (pEntry != pHead)
  3674. {
  3675. pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  3676. if (pDevContext->IpAddress == SrcAddress)
  3677. {
  3678. return(TRUE);
  3679. }
  3680. pEntry = pEntry->Flink;
  3681. }
  3682. return(FALSE);
  3683. }
  3684. //----------------------------------------------------------------------------
  3685. VOID
  3686. SwitchToBackup(
  3687. IN tDEVICECONTEXT *pDeviceContext
  3688. )
  3689. /*++
  3690. Routine Description:
  3691. This function switches the primary and backup name server addresses.
  3692. Arguments:
  3693. Return Value:
  3694. NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
  3695. --*/
  3696. {
  3697. ULONG SaveAddr;
  3698. //
  3699. // Bug: 30511: Dont switch servers if no backup.
  3700. //
  3701. if (pDeviceContext->lBackupServer == LOOP_BACK) {
  3702. IF_DBG(NBT_DEBUG_REFRESH)
  3703. KdPrint(("Nbt:Will not Switch to backup name server: devctx: %X, refreshtobackup=%X\n",
  3704. pDeviceContext, pDeviceContext->RefreshToBackup));
  3705. return;
  3706. }
  3707. SaveAddr = pDeviceContext->lNameServerAddress;
  3708. pDeviceContext->lNameServerAddress = pDeviceContext->lBackupServer;
  3709. pDeviceContext->lBackupServer = SaveAddr;
  3710. IF_DBG(NBT_DEBUG_REFRESH)
  3711. KdPrint(("Nbt:Switching to backup name server: devctx: %X, refreshtobackup=%X\n",
  3712. pDeviceContext, pDeviceContext->RefreshToBackup));
  3713. // keep track if we are on the backup or not.
  3714. pDeviceContext->RefreshToBackup = ~pDeviceContext->RefreshToBackup;
  3715. pDeviceContext->SwitchedToBackup = ~pDeviceContext->SwitchedToBackup;
  3716. }
  3717. //----------------------------------------------------------------------------
  3718. NTSTATUS
  3719. GetNbFlags(
  3720. IN tNAMEHDR UNALIGNED *pNameHdr,
  3721. IN LONG lNameSize,
  3722. IN LONG lNumBytes,
  3723. OUT USHORT *pRegType
  3724. )
  3725. /*++
  3726. Routine Description:
  3727. This function finds the Nbflags field in certain pdu types and returns it.
  3728. Arguments:
  3729. Return Value:
  3730. NTSTATUS - STATUS_SUCCESS or STATUS_REMOTE_NOT_LISTENING
  3731. Called By: RegResponseFromNet
  3732. --*/
  3733. {
  3734. LONG DnsLabelLength, Offset;
  3735. //
  3736. // Bug#s 125648, 125649
  3737. // The Data is packed in the form:
  3738. // tNameHdr --> TransactId ==> Offset 0, Length = 2 bytes
  3739. // :
  3740. // --> NameRR.NetbiosName ==> Offset=13, Length = lNameSize
  3741. // --> tGENERALRR ==> Offset=13+lNameSize, Length >= 22bytes
  3742. //
  3743. // We need to verify that the NameHdr contains the minimum Buffer space required
  3744. // to hold the entire PDU data
  3745. //
  3746. if (lNumBytes < (FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize + NBT_MINIMUM_RR_LENGTH))
  3747. {
  3748. ASSERT (0);
  3749. return (STATUS_UNSUCCESSFUL);
  3750. }
  3751. //
  3752. // if the question name is not a pointer to the first name then we
  3753. // must find the end of that name and adjust it so when added to
  3754. // to lNameSize we endup at NB_FLAGS
  3755. //
  3756. if ((pNameHdr->NameRR.NetBiosName[lNameSize+PTR_OFFSET] & PTR_SIGNATURE) != PTR_SIGNATURE)
  3757. {
  3758. // add one to include the null on the end of the string + the NB, IN TTL,
  3759. // and length fields( another 10 bytes NO_PTR_OFFSET) + PTR_OFFSET(4).
  3760. //
  3761. Offset = FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize + PTR_OFFSET;
  3762. if (STATUS_SUCCESS != (strnlen ((PUCHAR) &pNameHdr->NameRR.NetBiosName [lNameSize+PTR_OFFSET],
  3763. lNumBytes - (Offset+16), // +16 bytes to end of GeneralRR
  3764. &DnsLabelLength)))
  3765. {
  3766. ASSERT (0);
  3767. return (STATUS_UNSUCCESSFUL);
  3768. }
  3769. // add one to include the null on the end of the string
  3770. DnsLabelLength++;
  3771. }
  3772. else
  3773. {
  3774. DnsLabelLength = 2;
  3775. }
  3776. Offset = lNameSize+PTR_OFFSET+DnsLabelLength+NO_PTR_OFFSET;
  3777. *pRegType = ntohs((USHORT) pNameHdr->NameRR.NetBiosName[Offset]);
  3778. return (STATUS_SUCCESS);
  3779. }
  3780. //----------------------------------------------------------------------------
  3781. NTSTATUS
  3782. FindOnPendingList(
  3783. IN PUCHAR pName,
  3784. IN tNAMEHDR UNALIGNED *pNameHdr,
  3785. IN BOOLEAN DontCheckTransactionId,
  3786. IN ULONG BytesToCompare,
  3787. OUT tNAMEADDR **ppNameAddr
  3788. )
  3789. /*++
  3790. Routine Description:
  3791. This function is called to look for a name query request on the pending
  3792. list. It searches the list linearly to look for the name.
  3793. The Joint Lock is held when calling this routine.
  3794. Arguments:
  3795. Return Value:
  3796. --*/
  3797. {
  3798. PLIST_ENTRY pHead;
  3799. PLIST_ENTRY pEntry;
  3800. tNAMEADDR *pNameAddr;
  3801. tTIMERQENTRY *pTimer;
  3802. pHead = pEntry = &NbtConfig.PendingNameQueries;
  3803. while ((pEntry = pEntry->Flink) != pHead)
  3804. {
  3805. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  3806. //
  3807. // there could be multiple entries with the same name so check the
  3808. // transaction id too
  3809. //
  3810. if (DontCheckTransactionId ||
  3811. ((pTimer = pNameAddr->pTimer) &&
  3812. (((tDGRAM_SEND_TRACKING *)pTimer->Context)->TransactionId == pNameHdr->TransactId))
  3813. &&
  3814. (CTEMemEqu(pNameAddr->Name,pName,BytesToCompare)))
  3815. {
  3816. *ppNameAddr = pNameAddr;
  3817. return(STATUS_SUCCESS);
  3818. }
  3819. }
  3820. return(STATUS_UNSUCCESSFUL);
  3821. }
  3822. #if DBG
  3823. //----------------------------------------------------------------------------
  3824. VOID
  3825. PrintHexString(
  3826. IN tNAMEHDR UNALIGNED *pNameHdr,
  3827. IN ULONG lNumBytes
  3828. )
  3829. /*++
  3830. Routine Description:
  3831. This function is called to determine whether the name packet we heard on
  3832. the net has the same address as the one in the remote hash table.
  3833. If it has the same address or if it does not have any address, we return
  3834. SUCCESS, else we return NOT_LISTENING.
  3835. Arguments:
  3836. Return Value:
  3837. NTSTATUS - STATUS_SUCCESS or STATUS_REMOTE_NOT_LISTENING
  3838. Called By: RegResponseFromNet
  3839. --*/
  3840. {
  3841. ULONG i,Count=0;
  3842. PUCHAR pHdr=(PUCHAR)pNameHdr;
  3843. for (i=0;i<lNumBytes ;i++ )
  3844. {
  3845. KdPrint(("%2.2X ",*pHdr));
  3846. pHdr++;
  3847. if (Count >= 16)
  3848. {
  3849. Count = 0;
  3850. KdPrint(("\n"));
  3851. }
  3852. else
  3853. Count++;
  3854. }
  3855. KdPrint(("\n"));
  3856. }
  3857. #endif
  3858. #ifdef PROXY_NODE
  3859. //----------------------------------------------------------------------------
  3860. NTSTATUS
  3861. ChkIfValidRsp(
  3862. IN tNAMEHDR UNALIGNED *pNameHdr,
  3863. IN LONG lNameSize,
  3864. IN tNAMEADDR *pNameAddr
  3865. )
  3866. /*++
  3867. Routine Description:
  3868. This function is called to determine whether the name packet we heard on
  3869. the net has the same address as the one in the remote hash table.
  3870. If it has the same address or if it does not have any address, we return
  3871. SUCCESS, else we return NOT_LISTENING.
  3872. Arguments:
  3873. Return Value:
  3874. NTSTATUS - STATUS_SUCCESS or STATUS_REMOTE_NOT_LISTENING
  3875. Called By: RegResponseFromNet
  3876. --*/
  3877. {
  3878. ULONG IpAdd;
  3879. IpAdd = ntohl(
  3880. pNameHdr->NameRR.NetBiosName[lNameSize+IPADDRESS_OFFSET]
  3881. );
  3882. //
  3883. // If the IP address in the packet received is same as the one
  3884. // in the table we return success, else we are not interested
  3885. // in the packet (we want to just drop the packet)
  3886. //
  3887. if (
  3888. (IpAdd == pNameAddr->IpAddress)
  3889. )
  3890. {
  3891. return(STATUS_SUCCESS);
  3892. }
  3893. else
  3894. {
  3895. return(STATUS_REMOTE_NOT_LISTENING);
  3896. }
  3897. }
  3898. #endif