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.

342 lines
12 KiB

  1. //
  2. //
  3. // proxy.c
  4. //
  5. // This file contains the Proxy related functions that implement the Bnode
  6. // proxy functionality. This allows a Bnode to make use of a Name Service
  7. // transparently since the proxy code picks up the Bnode Query broadcasts directly
  8. // and either answers them directly or queries the NS and then answers them
  9. // later.
  10. // code
  11. #include "precomp.h"
  12. #include <ipinfo.h>
  13. #include "proxy.tmh"
  14. VOID
  15. ProxyClientCompletion(
  16. IN PVOID pContext,
  17. IN NTSTATUS status
  18. );
  19. #ifdef PROXY_NODE
  20. //----------------------------------------------------------------------------
  21. NTSTATUS
  22. RegOrQueryFromNet(
  23. IN BOOL fReg,
  24. IN tDEVICECONTEXT *pDeviceContext,
  25. IN tNAMEHDR UNALIGNED *pNameHdr,
  26. IN LONG lNameSize,
  27. IN PCHAR pNameInPkt,
  28. IN PUCHAR pScope
  29. )
  30. /*++
  31. Routine Description:
  32. This function handles a name registration/name overwrite or a name
  33. query that comes over the subnet. It checks the remote name table. If
  34. the name is there, the function simply returns. If the name is not
  35. there, the function calls QueryNameOnNet to add the name to the remote table
  36. (in the resolving state) and to query the NS.
  37. Note: If the name is there in the table, it may or may not have the same
  38. address as the registration that we got or it may be of a different
  39. type. Not doing anything for this case is ok as explained below.
  40. Arguments:
  41. Return Value:
  42. NTSTATUS - success or not - failure means no response to the net
  43. Called By:
  44. QueryFromNet() in inbound.c, NameSrvHndlrNotOs() in hndlrs.c
  45. --*/
  46. {
  47. tGENERALRR *pResrcRecord;
  48. ULONG IpAddress;
  49. BOOLEAN bGroupName;
  50. CTELockHandle OldIrq;
  51. PLIST_ENTRY pHead;
  52. PLIST_ENTRY pEntry;
  53. //
  54. // if we have heard a registration on the net, get the IP address
  55. // and the type of registration (unique/group) from the packet.
  56. //
  57. // if we have heard a query, use default values for the above two
  58. // fields
  59. //
  60. if (fReg)
  61. {
  62. // get the Ip address out of the Registration request
  63. pResrcRecord = (tGENERALRR *) &pNameHdr->NameRR.NetBiosName[lNameSize];
  64. IpAddress = ntohl(pResrcRecord->IpAddress);
  65. bGroupName = pResrcRecord->Flags & FL_GROUP;
  66. }
  67. else
  68. {
  69. IpAddress = 0;
  70. bGroupName = NBT_UNIQUE; //default value
  71. }
  72. //
  73. // The name is not there in the remote name table.
  74. // Add it in the RESOLVING state and send a name query
  75. // to the NS.
  76. //
  77. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  78. if (NbtConfig.ProxyType == PROXY_WINS) {
  79. NbtTrace(NBT_TRACE_PROXY, ("Send WINS Proxy query %!NBTNAME!<%02x> on %!ipaddr!",
  80. pNameInPkt, (unsigned)pNameInPkt[15], pDeviceContext->IpAddress));
  81. QueryNameOnNet (pNameInPkt,
  82. pScope,
  83. bGroupName,
  84. NULL, //client context
  85. ProxyClientCompletion,
  86. PROXY| (fReg?PROXY_REG: 0),
  87. NULL, //we want to add the name(pNameAddr = NULL)
  88. pDeviceContext,
  89. &OldIrq);
  90. } else {
  91. pHead = &NbtConfig.DeviceContexts;
  92. pEntry = pHead->Flink;
  93. while (pEntry != pHead) {
  94. tDEVICECONTEXT *dev;
  95. dev = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  96. pEntry = pEntry->Flink;
  97. /*
  98. * Make sure we are not getting the device from the DeviceAwaitingDeletion.
  99. * It could happen since QueryNameOnNet could temporarily release the JointLock.
  100. */
  101. if (dev->Verify != NBT_VERIFY_DEVCONTEXT) {
  102. break;
  103. }
  104. if (dev->IpAddress == 0 || dev->IpAddress == LOOP_BACK ||
  105. (!fReg && (dev->RasProxyFlags & PROXY_RAS_NONAMEQUERYFORWARDING))) {
  106. continue;
  107. }
  108. if (dev == pDeviceContext) {
  109. /* We don't want to broadcast back to the same interface through which we receive */
  110. continue;
  111. }
  112. /*
  113. * Reference the device so that it won't disappear inside QueryNameOnNet
  114. * Note: QueryNameOnNet may temporarily release the JointLock
  115. */
  116. NBT_REFERENCE_DEVICE(dev, REF_DEV_DGRAM, TRUE);
  117. NbtTrace(NBT_TRACE_PROXY, ("Send RAS Proxy query %!NBTNAME!<%02x> on %!ipaddr!",
  118. pNameInPkt, (unsigned)pNameInPkt[15], dev->IpAddress));
  119. QueryNameOnNet (pNameInPkt,
  120. pScope,
  121. bGroupName,
  122. NULL, //client context
  123. ProxyClientCompletion,
  124. PROXY| (fReg?PROXY_REG: 0),
  125. NULL, //we want to add the name(pNameAddr = NULL)
  126. dev,
  127. &OldIrq);
  128. /*
  129. * Since the QueryNameOnNet could release the lock temporarily, it is possible
  130. * that the device is deleted (removing from the NbtConfig.DeviceContexts
  131. * list) after QueryNameOnNet returns.
  132. * Worse than that, the pEntry may also be removed. The IP address of pEntry
  133. * will be 0.0.0.0 and pEntry->Flink == pEntry. We could end up with a indefinite
  134. * looping above.
  135. */
  136. pEntry = dev->Linkage.Flink;
  137. if (dev->IpAddress == 0 || dev->Verify != NBT_VERIFY_DEVCONTEXT || pEntry->Flink == pEntry) {
  138. /*
  139. * In this case, we cannot go ahead because dev->Linkage.Flink may not
  140. * be valid. pEntry may not be valid also. Simply stop here.
  141. */
  142. NBT_DEREFERENCE_DEVICE(dev, REF_DEV_DGRAM, TRUE);
  143. break;
  144. }
  145. NBT_DEREFERENCE_DEVICE(dev, REF_DEV_DGRAM, TRUE);
  146. }
  147. }
  148. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  149. return(STATUS_SUCCESS);
  150. }
  151. //----------------------------------------------------------------------------
  152. VOID
  153. ProxyTimerComplFn (
  154. IN PVOID pContext,
  155. IN PVOID pContext2,
  156. IN tTIMERQENTRY *pTimerQEntry
  157. )
  158. /*++
  159. Routine Description:
  160. This function either deletes the name from the remote name table
  161. if fReg is FALSE (i.e. the timer has expired on a name query
  162. sent by the Proxy on behalf of a node doing a name query) or changes
  163. the state to RESOLVED if fReg is TRUE (i.e. the timer has expired
  164. on a name query sent on behalf of a node doing name registration)
  165. Arguments:
  166. pfReg - indicates whether the timer expiry is for a name
  167. query
  168. Return Value:
  169. NTSTATUS - success or not - failure means no response to the net
  170. --*/
  171. {
  172. NTSTATUS status;
  173. tDGRAM_SEND_TRACKING *pTracker;
  174. CTELockHandle OldIrq;
  175. tNAMEADDR *pNameAddr;
  176. tNAMEADDR *pNameAddrNew;
  177. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  178. if (!pTimerQEntry)
  179. {
  180. // return the tracker block to its queue
  181. pTracker->pNameAddr->pTimer = NULL;
  182. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  183. NBT_DEREFERENCE_TRACKER (pTracker, TRUE);
  184. return;
  185. }
  186. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  187. if ((--pTimerQEntry->Retries) == 0) // The Retires have expired
  188. {
  189. if (!(pTracker->Flags & NBT_NAME_SERVER))
  190. {
  191. //
  192. // If pContext2 is not 0, it means that this timer function was
  193. // called by the proxy for a query which it sent on hearing a
  194. // registration on the net. If pContext2 is 0, it means
  195. // that the timer function was called by the proxy for a query
  196. // which it sent on hearing a query on the net.
  197. //
  198. pTimerQEntry->ClientCompletion = NULL;
  199. //
  200. // Mark the entry as released. Do not dereference the name
  201. // The entry will remain in the remote hash table. When the proxy
  202. // code sees a query or registration for a released entry in the
  203. // cache it does not query the name server. This cuts down on
  204. // name server traffic. The released entries are removed from
  205. // the cache at cache timer expiry (kept small).
  206. //************************************
  207. // Changed: Dereference the name because the name query timed
  208. // out meaning that we did not contact WINS, therefore we
  209. // do not know if the name is valid or not!
  210. //
  211. pNameAddr = pTracker->pNameAddr;
  212. CHECK_PTR(pNameAddr);
  213. pNameAddr->pTimer = NULL; // remove the link from the name table to this timer block
  214. // NBT_PROXY_DBG(("ProxyTimerComplFn: State of name %16.16s(%X) changed to (%s)\n", pTracker->pNameAddr->Name, pTracker->pNameAddr->Name[15], "RELEASED"));
  215. // Remove from the pending Queries list - and put into the hash
  216. // table for 1 minute so we do not beat up on WINS if it is down
  217. // or slow right now.
  218. //
  219. RemoveEntryList (&pNameAddr->Linkage);
  220. InitializeListHead (&pNameAddr->Linkage);
  221. status = AddToHashTable (NbtConfig.pRemoteHashTbl,
  222. pNameAddr->Name,
  223. NbtConfig.pScope,
  224. pNameAddr->IpAddress,
  225. NBT_UNIQUE,
  226. NULL,
  227. &pNameAddrNew,
  228. pTracker->pDeviceContext,
  229. NAME_RESOLVED_BY_WINS | NAME_RESOLVED_BY_BCAST);
  230. if (NT_SUCCESS(status))
  231. {
  232. pNameAddrNew->NameTypeState &= ~NAME_STATE_MASK;
  233. pNameAddrNew->NameTypeState |= STATE_RELEASED;
  234. pNameAddrNew->TimeOutCount = 60000 / REMOTE_HASH_TIMEOUT;
  235. }
  236. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  237. NBT_DEREFERENCE_TRACKER (pTracker, TRUE); // return the tracker block to its queue
  238. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  239. return;
  240. }
  241. //
  242. // Can't reach the name server, so try the backup
  243. //
  244. pTracker->Flags &= ~NBT_NAME_SERVER;
  245. pTracker->Flags |= NBT_NAME_SERVER_BACKUP;
  246. // set the retry count again
  247. pTimerQEntry->Retries = NbtConfig.uNumRetries;
  248. }
  249. NBT_REFERENCE_TRACKER (pTracker);
  250. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  251. status = UdpSendNSBcast(pTracker->pNameAddr,
  252. NbtConfig.pScope,
  253. pTracker,
  254. NULL,NULL,NULL,
  255. 0,0,
  256. eNAME_QUERY,
  257. TRUE);
  258. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  259. pTimerQEntry->Flags |= TIMER_RESTART;
  260. return;
  261. }
  262. //----------------------------------------------------------------------------
  263. VOID
  264. ProxyClientCompletion(
  265. IN PVOID pContext,
  266. IN NTSTATUS status
  267. )
  268. /*++
  269. Routine Description:
  270. This function does nothing since the proxy does not need to do anything
  271. when a name query succeeds. The code in inbound.c does all that
  272. is necessary - namely put the name in the name table.
  273. Arguments:
  274. Return Value:
  275. --*/
  276. {
  277. }
  278. #endif