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

/*++
Copyright (c) 1990, 1991 Microsoft Corporation
Module Name:
linktree.c
Abstract:
This module contains code which implements the management of the link
splay tree. This splay tree is maintained to minimize the lookup time
needed with each individual packet that comes in. To this end, we create a
ULARGE_INTEGER that contains the transport address of the remote and
do a ULARGE_INTEGER comaprison of the addresses (rather than comparing
the bytes 1 by 1). Assuming that the ULARGE_INTEGER comparison routines are
optimized for the hardware on the machine, this should be as fast as or
faster than comparing bytes.
DEBUG: there is currently code in the comparison routines that will let
me fine-tune the search and ordering algorithm as we gain more
experience with it.
Author:
David Beaver (dbeaver) 1-July-1991
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
NTSTATUS
NbfAddLinkToTree(
IN PDEVICE_CONTEXT DeviceContext,
IN PTP_LINK Link
)
/*++
Routine Description:
This routine adds a link to the tree of links maintained for this device.
Note that since this routine needs to modify the link tree, it is called
in the context of a deferred processing routine, and must have exclusive
access to the tree. The spinlock is taken by the routine that calls this
one, as this operation must be atomic in the eyes of the rest of NBF.
Note further that this routine insists that there not be a link with this
address in the tree.
As the final operation of this insertion, the splay tree is balanced.
Arguments:
Link - Pointer to a transport link object.
Return Value:
STATUS_SUCCESS if the link is successfully added,
STATUS_DRIVER_INTERNAL_ERROR if there was a problem adding
the link (implying the tree was in a bad state).
--*/
{
PTP_LINK treeLink;
PRTL_SPLAY_LINKS linkLink;
//
// initialize the link and check for the trivial case.
//
RtlInitializeSplayLinks (Link);
linkLink = DeviceContext->LinkTreeRoot;
if (linkLink == NULL) { // null tree, make this the parent
DeviceContext->LinkTreeRoot = (PRTL_SPLAY_LINKS)Link;
DeviceContext->LinkTreeElements++;
DeviceContext->LastLink = Link;
return STATUS_SUCCESS;
}
//
// Wasn't a null tree, so set up for the addition
//
treeLink = (PTP_LINK) linkLink;
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint1 ("NbfAddLinkToTree: starting insert, Elements: %ld \n",DeviceContext->LinkTreeElements);
}
//
// find the proper spot to put this link.
//
do {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint3 ("NbfAddLinkToTree: searching, Link: %lx LC: %lx RC: %lx\n",
linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
}
//
// Bad news == means we already have this link, someone is messed up.
// it's possible to be adding and deleting things at the same time;
// that's
//
if ((treeLink->MagicAddress).QuadPart == (Link->MagicAddress).QuadPart) {
//
// First make sure we don't have the splay tree in a loop.
//
ASSERT (treeLink != Link);
//
// This link is already in the tree. This is OK if it is
// due to be deleted; we can just do the delete right now,
// since AddLinkToTree is only called from the deferred
// timer routine.
//
if (treeLink->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) {
//
// It will be in the deferred list. We remove it,
// we don't worry about LinkDeferredActive since
// the timeout routine that is calling us handles
// that.
//
RemoveEntryList (&treeLink->DeferredList);
treeLink->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
NbfRemoveLinkFromTree (DeviceContext, treeLink);
NbfDestroyLink (treeLink);
#if DBG
NbfPrint2 ("NbfAddLinkToTree: Link %lx removed for %lx\n",
treeLink, Link);
#endif
//
// Now that that link is out of the tree, call
// ourselves recursively to do the insert.
//
return NbfAddLinkToTree (DeviceContext, Link);
} else {
ASSERTMSG ("NbfAddLinkToTree: Found identical Link in tree!\n", FALSE);
return STATUS_DRIVER_INTERNAL_ERROR;
}
}
//
// traverse the tree for the correct spot
//
if ((Link->MagicAddress).QuadPart < (treeLink->MagicAddress).QuadPart) {
if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfAddLinkToTree: Adding link as LC.\n");
}
RtlInsertAsLeftChild ((PRTL_SPLAY_LINKS)treeLink,
(PRTL_SPLAY_LINKS)Link);
// DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
DeviceContext->LinkTreeElements++;
return STATUS_SUCCESS;
} else {
treeLink = (PTP_LINK) linkLink;
continue;
} // Left Child
} else { // is greater
if ((linkLink = RtlRightChild (linkLink)) == NULL) {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfAddLinkToTree: Adding link as RC.\n");
}
RtlInsertAsRightChild ((PRTL_SPLAY_LINKS)treeLink,
(PRTL_SPLAY_LINKS)Link);
// DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
DeviceContext->LinkTreeElements++;
return STATUS_SUCCESS;
} else {
treeLink = (PTP_LINK) linkLink;
continue;
} // Right Child
} // end else addresses comparison
} while (TRUE);
} // NbfAddLinkToTree
NTSTATUS
NbfRemoveLinkFromTree(
IN PDEVICE_CONTEXT DeviceContext,
IN PTP_LINK Link
)
/*++
Routine Description:
This routine removes a link from the tree of links.
Note that since this routine needs to modify the link tree, it is called
in the context of a deferred processing routine, and must have exclusive
access to the tree. The spinlock is taken by the routine that calls this
one, as this operation must be atomic in the eyes of the rest of NBF.
Note further that this routine insists that there not be a link with this
address in the tree.
Arguments:
Link - Pointer to a transport link object.
DeviceContext - pointer to the device context on which this
Return Value:
STATUS_SUCCESS if the link was removed,
STATUS_DRIVER_INTERNAL_ERROR if there was a problem removing
the link (implying the tree was in a bad state).
--*/
{
DeviceContext->LinkTreeRoot = RtlDelete ((PRTL_SPLAY_LINKS)Link);
DeviceContext->LinkTreeElements--;
if (DeviceContext->LastLink == Link) {
DeviceContext->LastLink = (PTP_LINK)DeviceContext->LinkTreeRoot;
}
return STATUS_SUCCESS;
} //NbfRemoveLinkFromTree
PTP_LINK
NbfFindLinkInTree(
IN PDEVICE_CONTEXT DeviceContext,
IN PUCHAR Remote
)
/*++
Routine Description:
This routine traverses the link tree looking for the given remote address.
The link tree spinlock is held while looking for the link. After the link
is found, it's reference count is incremented.
NOTE: This function is called with the device context LinkSpinLock
held.
Arguments:
DeviceContext - pointer to the device this address is associated with.
Remote - pointer to the hardware address of the remote node.
Return Value:
Pointer to the link in the tree that matches this remote address. If
no link is found, NULL is returned.
--*/
{
PTP_LINK link;
PRTL_SPLAY_LINKS linkLink;
ULARGE_INTEGER Magic = {0,0};
//
// Are there even any links in the tree?
//
if (DeviceContext->LinkTreeElements <= 0) {
return NULL;
}
linkLink = DeviceContext->LinkTreeRoot;
//
// Make a magic number for this link
//
MacReturnMagicAddress (&DeviceContext->MacInfo, Remote, &Magic);
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint1 ("NbfFindLinkInTree: starting search, Elements: %ld \n",
DeviceContext->LinkTreeElements);
}
//
// Do a quick check if the last link found is this one.
//
ASSERT (DeviceContext->LastLink != NULL);
if ((DeviceContext->LastLink->MagicAddress).QuadPart == Magic.QuadPart) {
link = DeviceContext->LastLink;
} else {
//
// find the link.
//
link = (PTP_LINK) linkLink; // depends upon splay links being first
// subfield in link!
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint3 ("NbfFindLinkInTree: searching, Link: %lx LC: %lx RC: %lx \n",
linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
}
do {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint4 ("NbfFindLinkInTree: Comparing: %lx%lx to %lx%lx\n",
link->MagicAddress.HighPart,link->MagicAddress.LowPart,
Magic.HighPart, Magic.LowPart);
}
if ((link->MagicAddress).QuadPart == Magic.QuadPart) {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfFindLinkInTree: equal, going to end.\n");
}
break;
} else {
if ((link->MagicAddress).QuadPart < Magic.QuadPart) {
if ((linkLink = RtlRightChild (linkLink)) == NULL) {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
}
return NULL;
} else {
link = (PTP_LINK) linkLink;
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint3 ("NbfFindLinkInTree: less, took right child, Link: %lx LC: %lx RC: %lx \n",
linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
}
continue;
}
} else { // is greater
if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
}
return NULL;
} else {
link = (PTP_LINK) linkLink;
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint3 ("NbfFindLinkInTree: greater, took left child, Link: %lx LC: %lx RC: %lx \n",
linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
}
continue;
} // got left child branch
} // greater branch
} // equal to branch
} while (TRUE);
DeviceContext->LastLink = link;
}
//
// Only break out when we've actually found a match..
//
if ((link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfFindLinkInTree: Link Found but delete pending.\n");
}
return NULL;
}
//
// Mark the link as in use and say we don't need the tree stable any more.
//
NbfReferenceLink ("Found in tree", link, LREF_TREE);
IF_NBFDBG(NBF_DEBUG_LINKTREE) {
NbfPrint0 ("NbfFindLinkInTree: Link Found.\n");
}
return link;
} // NbfFindLinkInTree
PTP_LINK
NbfFindLink(
IN PDEVICE_CONTEXT DeviceContext,
IN PUCHAR Remote
)
/*++
Routine Description:
This routine looks for a link in the link tree, and if
not found there in the deferred queue.
Arguments:
DeviceContext - pointer to the device this address is associated with.
Remote - pointer to the hardware address of the remote node.
Return Value:
Pointer to the link in the tree that matches this remote address. If
no link is found, NULL is returned.
--*/
{
PTP_LINK Link;
BOOLEAN MatchedLink;
PLIST_ENTRY p;
UINT i;
ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
Link = NbfFindLinkInTree (DeviceContext, Remote);
if (Link == NULL) {
//
// Not found there, try in deferred queue.
//
MatchedLink = FALSE; // Assume failure
//
// Hold the spinlock while we walk the deferred list. We need
// TimerSpinLock to stop the list from changing, and we need
// LinkSpinLock to synchronize checking DEFERRED_DELETE and
// referencing the link.
//
ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
for (p = DeviceContext->LinkDeferred.Flink;
p != &DeviceContext->LinkDeferred;
p = p->Flink) {
//
// What about taking a lock while we walk
// this list? It won't be removed from at the front,
// but it may be added to at the back.
//
//
// We're probably still getting this link to the splay tree.
// find it and process normally.
//
Link = CONTAINING_RECORD (p, TP_LINK, DeferredList);
//
// NOTE: We know that the link is not going to be destroyed
// now, because we have increased the semaphore. We
// reference the link if DEFERRED_DELETE is not on; the
// setting of this flag is synchronized (also using
// DeviceContext->LinkSpinLock) with the refcount going
// to 0).
//
if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
continue; // we're deleting link, can't handle
}
for (i=0; i<(UINT)DeviceContext->MacInfo.AddressLength; i++) {
if (Remote[i] != Link->HardwareAddress.Address[i]){
break;
}
}
if (i == (UINT)DeviceContext->MacInfo.AddressLength) { // addresses match. Deliver packet.
IF_NBFDBG (NBF_DEBUG_DLC) {
NbfPrint1 ("NbfFindLink: Found link on deferred queue, Link: %lx\n",
Link);
}
NbfReferenceLink ("Got Frame on Deferred", Link, LREF_TREE);
MatchedLink = TRUE;
break;
}
}
RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
//
// If this didn't find the link, make note of that.
//
if (MatchedLink == FALSE) {
Link = (PTP_LINK)NULL;
}
} else {
IF_NBFDBG (NBF_DEBUG_DLC) {
NbfPrint1 ("NbfFindLink: Found link in tree, Link: %lx\n", Link);
}
}
RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
return Link;
}