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.

537 lines
15 KiB

  1. /*++
  2. Copyright (c) 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. linktree.c
  5. Abstract:
  6. This module contains code which implements the management of the link
  7. splay tree. This splay tree is maintained to minimize the lookup time
  8. needed with each individual packet that comes in. To this end, we create a
  9. ULARGE_INTEGER that contains the transport address of the remote and
  10. do a ULARGE_INTEGER comaprison of the addresses (rather than comparing
  11. the bytes 1 by 1). Assuming that the ULARGE_INTEGER comparison routines are
  12. optimized for the hardware on the machine, this should be as fast as or
  13. faster than comparing bytes.
  14. DEBUG: there is currently code in the comparison routines that will let
  15. me fine-tune the search and ordering algorithm as we gain more
  16. experience with it.
  17. Author:
  18. David Beaver (dbeaver) 1-July-1991
  19. Environment:
  20. Kernel mode
  21. Revision History:
  22. --*/
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. NTSTATUS
  26. NbfAddLinkToTree(
  27. IN PDEVICE_CONTEXT DeviceContext,
  28. IN PTP_LINK Link
  29. )
  30. /*++
  31. Routine Description:
  32. This routine adds a link to the tree of links maintained for this device.
  33. Note that since this routine needs to modify the link tree, it is called
  34. in the context of a deferred processing routine, and must have exclusive
  35. access to the tree. The spinlock is taken by the routine that calls this
  36. one, as this operation must be atomic in the eyes of the rest of NBF.
  37. Note further that this routine insists that there not be a link with this
  38. address in the tree.
  39. As the final operation of this insertion, the splay tree is balanced.
  40. Arguments:
  41. Link - Pointer to a transport link object.
  42. Return Value:
  43. STATUS_SUCCESS if the link is successfully added,
  44. STATUS_DRIVER_INTERNAL_ERROR if there was a problem adding
  45. the link (implying the tree was in a bad state).
  46. --*/
  47. {
  48. PTP_LINK treeLink;
  49. PRTL_SPLAY_LINKS linkLink;
  50. //
  51. // initialize the link and check for the trivial case.
  52. //
  53. RtlInitializeSplayLinks (Link);
  54. linkLink = DeviceContext->LinkTreeRoot;
  55. if (linkLink == NULL) { // null tree, make this the parent
  56. DeviceContext->LinkTreeRoot = (PRTL_SPLAY_LINKS)Link;
  57. DeviceContext->LinkTreeElements++;
  58. DeviceContext->LastLink = Link;
  59. return STATUS_SUCCESS;
  60. }
  61. //
  62. // Wasn't a null tree, so set up for the addition
  63. //
  64. treeLink = (PTP_LINK) linkLink;
  65. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  66. NbfPrint1 ("NbfAddLinkToTree: starting insert, Elements: %ld \n",DeviceContext->LinkTreeElements);
  67. }
  68. //
  69. // find the proper spot to put this link.
  70. //
  71. do {
  72. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  73. NbfPrint3 ("NbfAddLinkToTree: searching, Link: %lx LC: %lx RC: %lx\n",
  74. linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
  75. }
  76. //
  77. // Bad news == means we already have this link, someone is messed up.
  78. // it's possible to be adding and deleting things at the same time;
  79. // that's
  80. //
  81. if ((treeLink->MagicAddress).QuadPart == (Link->MagicAddress).QuadPart) {
  82. //
  83. // First make sure we don't have the splay tree in a loop.
  84. //
  85. ASSERT (treeLink != Link);
  86. //
  87. // This link is already in the tree. This is OK if it is
  88. // due to be deleted; we can just do the delete right now,
  89. // since AddLinkToTree is only called from the deferred
  90. // timer routine.
  91. //
  92. if (treeLink->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) {
  93. //
  94. // It will be in the deferred list. We remove it,
  95. // we don't worry about LinkDeferredActive since
  96. // the timeout routine that is calling us handles
  97. // that.
  98. //
  99. RemoveEntryList (&treeLink->DeferredList);
  100. treeLink->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
  101. NbfRemoveLinkFromTree (DeviceContext, treeLink);
  102. NbfDestroyLink (treeLink);
  103. #if DBG
  104. NbfPrint2 ("NbfAddLinkToTree: Link %lx removed for %lx\n",
  105. treeLink, Link);
  106. #endif
  107. //
  108. // Now that that link is out of the tree, call
  109. // ourselves recursively to do the insert.
  110. //
  111. return NbfAddLinkToTree (DeviceContext, Link);
  112. } else {
  113. ASSERTMSG ("NbfAddLinkToTree: Found identical Link in tree!\n", FALSE);
  114. return STATUS_DRIVER_INTERNAL_ERROR;
  115. }
  116. }
  117. //
  118. // traverse the tree for the correct spot
  119. //
  120. if ((Link->MagicAddress).QuadPart < (treeLink->MagicAddress).QuadPart) {
  121. if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
  122. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  123. NbfPrint0 ("NbfAddLinkToTree: Adding link as LC.\n");
  124. }
  125. RtlInsertAsLeftChild ((PRTL_SPLAY_LINKS)treeLink,
  126. (PRTL_SPLAY_LINKS)Link);
  127. // DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
  128. DeviceContext->LinkTreeElements++;
  129. return STATUS_SUCCESS;
  130. } else {
  131. treeLink = (PTP_LINK) linkLink;
  132. continue;
  133. } // Left Child
  134. } else { // is greater
  135. if ((linkLink = RtlRightChild (linkLink)) == NULL) {
  136. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  137. NbfPrint0 ("NbfAddLinkToTree: Adding link as RC.\n");
  138. }
  139. RtlInsertAsRightChild ((PRTL_SPLAY_LINKS)treeLink,
  140. (PRTL_SPLAY_LINKS)Link);
  141. // DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
  142. DeviceContext->LinkTreeElements++;
  143. return STATUS_SUCCESS;
  144. } else {
  145. treeLink = (PTP_LINK) linkLink;
  146. continue;
  147. } // Right Child
  148. } // end else addresses comparison
  149. } while (TRUE);
  150. } // NbfAddLinkToTree
  151. NTSTATUS
  152. NbfRemoveLinkFromTree(
  153. IN PDEVICE_CONTEXT DeviceContext,
  154. IN PTP_LINK Link
  155. )
  156. /*++
  157. Routine Description:
  158. This routine removes a link from the tree of links.
  159. Note that since this routine needs to modify the link tree, it is called
  160. in the context of a deferred processing routine, and must have exclusive
  161. access to the tree. The spinlock is taken by the routine that calls this
  162. one, as this operation must be atomic in the eyes of the rest of NBF.
  163. Note further that this routine insists that there not be a link with this
  164. address in the tree.
  165. Arguments:
  166. Link - Pointer to a transport link object.
  167. DeviceContext - pointer to the device context on which this
  168. Return Value:
  169. STATUS_SUCCESS if the link was removed,
  170. STATUS_DRIVER_INTERNAL_ERROR if there was a problem removing
  171. the link (implying the tree was in a bad state).
  172. --*/
  173. {
  174. DeviceContext->LinkTreeRoot = RtlDelete ((PRTL_SPLAY_LINKS)Link);
  175. DeviceContext->LinkTreeElements--;
  176. if (DeviceContext->LastLink == Link) {
  177. DeviceContext->LastLink = (PTP_LINK)DeviceContext->LinkTreeRoot;
  178. }
  179. return STATUS_SUCCESS;
  180. } //NbfRemoveLinkFromTree
  181. PTP_LINK
  182. NbfFindLinkInTree(
  183. IN PDEVICE_CONTEXT DeviceContext,
  184. IN PUCHAR Remote
  185. )
  186. /*++
  187. Routine Description:
  188. This routine traverses the link tree looking for the given remote address.
  189. The link tree spinlock is held while looking for the link. After the link
  190. is found, it's reference count is incremented.
  191. NOTE: This function is called with the device context LinkSpinLock
  192. held.
  193. Arguments:
  194. DeviceContext - pointer to the device this address is associated with.
  195. Remote - pointer to the hardware address of the remote node.
  196. Return Value:
  197. Pointer to the link in the tree that matches this remote address. If
  198. no link is found, NULL is returned.
  199. --*/
  200. {
  201. PTP_LINK link;
  202. PRTL_SPLAY_LINKS linkLink;
  203. ULARGE_INTEGER Magic = {0,0};
  204. //
  205. // Are there even any links in the tree?
  206. //
  207. if (DeviceContext->LinkTreeElements <= 0) {
  208. return NULL;
  209. }
  210. linkLink = DeviceContext->LinkTreeRoot;
  211. //
  212. // Make a magic number for this link
  213. //
  214. MacReturnMagicAddress (&DeviceContext->MacInfo, Remote, &Magic);
  215. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  216. NbfPrint1 ("NbfFindLinkInTree: starting search, Elements: %ld \n",
  217. DeviceContext->LinkTreeElements);
  218. }
  219. //
  220. // Do a quick check if the last link found is this one.
  221. //
  222. ASSERT (DeviceContext->LastLink != NULL);
  223. if ((DeviceContext->LastLink->MagicAddress).QuadPart == Magic.QuadPart) {
  224. link = DeviceContext->LastLink;
  225. } else {
  226. //
  227. // find the link.
  228. //
  229. link = (PTP_LINK) linkLink; // depends upon splay links being first
  230. // subfield in link!
  231. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  232. NbfPrint3 ("NbfFindLinkInTree: searching, Link: %lx LC: %lx RC: %lx \n",
  233. linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
  234. }
  235. do {
  236. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  237. NbfPrint4 ("NbfFindLinkInTree: Comparing: %lx%lx to %lx%lx\n",
  238. link->MagicAddress.HighPart,link->MagicAddress.LowPart,
  239. Magic.HighPart, Magic.LowPart);
  240. }
  241. if ((link->MagicAddress).QuadPart == Magic.QuadPart) {
  242. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  243. NbfPrint0 ("NbfFindLinkInTree: equal, going to end.\n");
  244. }
  245. break;
  246. } else {
  247. if ((link->MagicAddress).QuadPart < Magic.QuadPart) {
  248. if ((linkLink = RtlRightChild (linkLink)) == NULL) {
  249. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  250. NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
  251. }
  252. return NULL;
  253. } else {
  254. link = (PTP_LINK) linkLink;
  255. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  256. NbfPrint3 ("NbfFindLinkInTree: less, took right child, Link: %lx LC: %lx RC: %lx \n",
  257. linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
  258. }
  259. continue;
  260. }
  261. } else { // is greater
  262. if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
  263. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  264. NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
  265. }
  266. return NULL;
  267. } else {
  268. link = (PTP_LINK) linkLink;
  269. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  270. NbfPrint3 ("NbfFindLinkInTree: greater, took left child, Link: %lx LC: %lx RC: %lx \n",
  271. linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
  272. }
  273. continue;
  274. } // got left child branch
  275. } // greater branch
  276. } // equal to branch
  277. } while (TRUE);
  278. DeviceContext->LastLink = link;
  279. }
  280. //
  281. // Only break out when we've actually found a match..
  282. //
  283. if ((link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
  284. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  285. NbfPrint0 ("NbfFindLinkInTree: Link Found but delete pending.\n");
  286. }
  287. return NULL;
  288. }
  289. //
  290. // Mark the link as in use and say we don't need the tree stable any more.
  291. //
  292. NbfReferenceLink ("Found in tree", link, LREF_TREE);
  293. IF_NBFDBG(NBF_DEBUG_LINKTREE) {
  294. NbfPrint0 ("NbfFindLinkInTree: Link Found.\n");
  295. }
  296. return link;
  297. } // NbfFindLinkInTree
  298. PTP_LINK
  299. NbfFindLink(
  300. IN PDEVICE_CONTEXT DeviceContext,
  301. IN PUCHAR Remote
  302. )
  303. /*++
  304. Routine Description:
  305. This routine looks for a link in the link tree, and if
  306. not found there in the deferred queue.
  307. Arguments:
  308. DeviceContext - pointer to the device this address is associated with.
  309. Remote - pointer to the hardware address of the remote node.
  310. Return Value:
  311. Pointer to the link in the tree that matches this remote address. If
  312. no link is found, NULL is returned.
  313. --*/
  314. {
  315. PTP_LINK Link;
  316. BOOLEAN MatchedLink;
  317. PLIST_ENTRY p;
  318. UINT i;
  319. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  320. Link = NbfFindLinkInTree (DeviceContext, Remote);
  321. if (Link == NULL) {
  322. //
  323. // Not found there, try in deferred queue.
  324. //
  325. MatchedLink = FALSE; // Assume failure
  326. //
  327. // Hold the spinlock while we walk the deferred list. We need
  328. // TimerSpinLock to stop the list from changing, and we need
  329. // LinkSpinLock to synchronize checking DEFERRED_DELETE and
  330. // referencing the link.
  331. //
  332. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  333. for (p = DeviceContext->LinkDeferred.Flink;
  334. p != &DeviceContext->LinkDeferred;
  335. p = p->Flink) {
  336. //
  337. // What about taking a lock while we walk
  338. // this list? It won't be removed from at the front,
  339. // but it may be added to at the back.
  340. //
  341. //
  342. // We're probably still getting this link to the splay tree.
  343. // find it and process normally.
  344. //
  345. Link = CONTAINING_RECORD (p, TP_LINK, DeferredList);
  346. //
  347. // NOTE: We know that the link is not going to be destroyed
  348. // now, because we have increased the semaphore. We
  349. // reference the link if DEFERRED_DELETE is not on; the
  350. // setting of this flag is synchronized (also using
  351. // DeviceContext->LinkSpinLock) with the refcount going
  352. // to 0).
  353. //
  354. if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
  355. continue; // we're deleting link, can't handle
  356. }
  357. for (i=0; i<(UINT)DeviceContext->MacInfo.AddressLength; i++) {
  358. if (Remote[i] != Link->HardwareAddress.Address[i]){
  359. break;
  360. }
  361. }
  362. if (i == (UINT)DeviceContext->MacInfo.AddressLength) { // addresses match. Deliver packet.
  363. IF_NBFDBG (NBF_DEBUG_DLC) {
  364. NbfPrint1 ("NbfFindLink: Found link on deferred queue, Link: %lx\n",
  365. Link);
  366. }
  367. NbfReferenceLink ("Got Frame on Deferred", Link, LREF_TREE);
  368. MatchedLink = TRUE;
  369. break;
  370. }
  371. }
  372. RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
  373. //
  374. // If this didn't find the link, make note of that.
  375. //
  376. if (MatchedLink == FALSE) {
  377. Link = (PTP_LINK)NULL;
  378. }
  379. } else {
  380. IF_NBFDBG (NBF_DEBUG_DLC) {
  381. NbfPrint1 ("NbfFindLink: Found link in tree, Link: %lx\n", Link);
  382. }
  383. }
  384. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  385. return Link;
  386. }