Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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