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

1180 lines
29 KiB

/*++
Copyright (c) 1997-2001 Microsoft Corporation
Module Name:
NsConn.c
Abstract:
IpSec NAT shim connection entry management
Author:
Jonathan Burstein (jonburs) 11-July-2001
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Global Variables
//
CACHE_ENTRY NsConnectionCache[CACHE_SIZE];
ULONG NsConnectionCount;
LIST_ENTRY NsConnectionList;
KSPIN_LOCK NsConnectionLock;
NPAGED_LOOKASIDE_LIST NsConnectionLookasideList;
PNS_CONNECTION_ENTRY NsConnectionTree[NsMaximumDirection];
USHORT NsNextSourcePort;
//
// Function Prototypes
//
PNS_CONNECTION_ENTRY
NspInsertInboundConnectionEntry(
PNS_CONNECTION_ENTRY pParent,
PNS_CONNECTION_ENTRY pEntry
);
PNS_CONNECTION_ENTRY
NspInsertOutboundConnectionEntry(
PNS_CONNECTION_ENTRY pParent,
PNS_CONNECTION_ENTRY pEntry
);
NTSTATUS
NsAllocateSourcePort(
ULONG64 ul64AddressKey,
ULONG ulPortKey,
UCHAR ucProtocol,
BOOLEAN fPortConflicts,
PNS_CONNECTION_ENTRY *ppOutboundInsertionPoint,
PULONG pulTranslatedPortKey
)
/*++
Routine Description:
Called to allocate a source port for a connection entry. If the original
port does not conflict with any existing connection entry it will be used.
Arguments:
ul64AddressKey - the addressing information for the connection
ulPortKey - the original port information for the connection
ucProtocol - the protocol for the connection
fPortConflicts - if TRUE, indicates that the caller knows that the original
port information conflicts w/ an existing connection. If FALSE the
caller does not know whether or not a conflict definately exists.
ppOutboundInsertionPoint - receives the insertion point for the
outbound path
pulTranslatedPortKey - on success, receives the allocated port information.
Return Value:
NTSTATUS.
Environment:
Invoked with NsConnectionLock held by the caller.
--*/
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
ULONG ulOutboundPortKey;
USHORT usLocalPort;
USHORT usStopPort;
ASSERT(NULL != ppOutboundInsertionPoint);
ASSERT(NULL != pulTranslatedPortKey);
TRACE(
PORT_ALLOC,
("NsAllocateSourcePort: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d\n",
ucProtocol,
ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_REMOTE_PORT(ulPortKey)),
ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_LOCAL_PORT(ulPortKey))
));
usLocalPort = CONNECTION_LOCAL_PORT(ulPortKey);
if (FALSE == fPortConflicts)
{
//
// The caller indicates that the remote port does not
// conflict on the inbound path, so we'll first attempt
// to use the original port.
//
ulOutboundPortKey = ulPortKey;
usStopPort =
(NS_SOURCE_PORT_END == NsNextSourcePort
? NS_SOURCE_PORT_BASE
: NsNextSourcePort + 1);
}
else
{
//
// The caller indicates that the remote port conflicts
// on the inbound path, so we'll assume that it also
// conflicts on the outbound path and start by trying
// out a new port.
//
usStopPort = NsNextSourcePort--;
MAKE_PORT_KEY(
ulOutboundPortKey,
usLocalPort,
usStopPort
);
if (NsNextSourcePort < NS_SOURCE_PORT_BASE)
{
NsNextSourcePort = NS_SOURCE_PORT_END;
}
}
do
{
//
// Check to see if our current candidate conflicts
// with any connection entries on the outbound path.
//
if (NULL ==
NsLookupOutboundConnectionEntry(
ul64AddressKey,
ulOutboundPortKey,
ucProtocol,
ppOutboundInsertionPoint
))
{
//
// No conflict was found -- break out of the loop and
// return this info to the caller.
//
TRACE(PORT_ALLOC, ("NsAllocateSourcePort: Assigning %d\n",
NTOHS(CONNECTION_REMOTE_PORT(ulOutboundPortKey))));
*pulTranslatedPortKey = ulOutboundPortKey;
Status = STATUS_SUCCESS;
break;
}
//
// This candidate conflicted; move on to the next.
//
MAKE_PORT_KEY(
ulOutboundPortKey,
usLocalPort,
NsNextSourcePort--
);
if (NsNextSourcePort < NS_SOURCE_PORT_BASE)
{
NsNextSourcePort = NS_SOURCE_PORT_END;
}
}
while (usStopPort != CONNECTION_REMOTE_PORT(ulOutboundPortKey));
TRACE(PORT_ALLOC, ("NsAllocateSourcePort: No port available\n"));
return Status;
} // NsAllocateSourcePort
VOID
NsCleanupConnectionEntry(
PNS_CONNECTION_ENTRY pEntry
)
/*++
Routine Description:
Called to perform final cleanup for a connection entry.
Arguments:
pEntry - the connection entry to be deleted.
Return Value:
none.
Environment:
Invoked with the last reference to the connection entry released.
--*/
{
TRACE(CONN_LIFETIME, ("NsCleanupConnectionEntry\n"));
ASSERT(NULL != pEntry);
FREE_CONNECTION_BLOCK(pEntry);
} // NsCleanupConnectionEntry
NTSTATUS
NsCreateConnectionEntry(
ULONG64 ul64AddressKey,
ULONG ulInboundPortKey,
ULONG ulOutboundPortKey,
UCHAR ucProtocol,
PVOID pvIpSecContext,
PNS_CONNECTION_ENTRY pInboundInsertionPoint,
PNS_CONNECTION_ENTRY pOutboundInsertionPoint,
PNS_CONNECTION_ENTRY *ppNewEntry
)
/*++
Routine Description:
Called to create a connection entry. On success, the connection entry
will have been referenced twice -- the initial reference for the entry
(which is released in NsDeleteConnectionEntry) and a reference for the
caller. Thus, the caller must call NsDereferenceConnectionEntry on the
new entry.
Arguments:
ul64AddressKey - the addressing information for this entry
ulInboundPortKey - the inbound (original) ports for this entry
ulOutboundPortKey - the outbound (translated) ports for this entry
ucProtocol - the protocol for this entry
pvIpSecContext - the IpSec context for this entry
p*InsertionPoint - the inbound and outbound insertion points (normally
obtained through NsAllocateSourcePort).
ppEntry - receives a pointer to the newley-created connection entry. The
caller must call NsDereferenceConnectionEntry on this pointer.
Return Value:
NTSTATUS - indicates success/failure.
Environment:
Invoked with 'NsConnectionLock' held by the caller.
--*/
{
PNS_CONNECTION_ENTRY pEntry;
TRACE(
CONN_LIFETIME,
("NsCreateConnectionEntry: %d: %d.%d.%d.%d/%d/%d -> %d.%d.%d.%d/%d : %d\n",
ucProtocol,
ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_REMOTE_PORT(ulInboundPortKey)),
NTOHS(CONNECTION_REMOTE_PORT(ulOutboundPortKey)),
ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_LOCAL_PORT(ulInboundPortKey)),
pvIpSecContext
));
ASSERT(NULL != ppNewEntry);
ASSERT(NS_PROTOCOL_TCP == ucProtocol || NS_PROTOCOL_UDP == ucProtocol);
pEntry = ALLOCATE_CONNECTION_BLOCK();
if (NULL == pEntry)
{
ERROR(("NsCreateConnectionEntry: Unable to allocate entry\n"));
return STATUS_NO_MEMORY;
}
RtlZeroMemory(pEntry, sizeof(*pEntry));
KeInitializeSpinLock(&pEntry->Lock);
pEntry->ulReferenceCount = 1;
pEntry->ul64AddressKey = ul64AddressKey;
pEntry->ulPortKey[NsInboundDirection] = ulInboundPortKey;
pEntry->ulPortKey[NsOutboundDirection] = ulOutboundPortKey;
pEntry->ucProtocol = ucProtocol;
pEntry->pvIpSecContext = pvIpSecContext;
pEntry->ulAccessCount[NsInboundDirection] = NS_CONNECTION_RESPLAY_THRESHOLD;
pEntry->ulAccessCount[NsOutboundDirection] = NS_CONNECTION_RESPLAY_THRESHOLD;
InitializeListHead(&pEntry->Link);
RtlInitializeSplayLinks(&pEntry->SLink[NsInboundDirection]);
RtlInitializeSplayLinks(&pEntry->SLink[NsOutboundDirection]);
//
// Incremeent the reference count on the connection; the caller
// is required to do a dereference.
//
pEntry->ulReferenceCount += 1;
//
// Setup checksum deltas (if necessary) and per-packet routines
//
if (ulInboundPortKey != ulOutboundPortKey)
{
//
// This connection entry is translating the remote port, so
// precompute the checksum deltas (see RFC 1624).
//
pEntry->ulProtocolChecksumDelta[NsInboundDirection] =
(USHORT)~CONNECTION_REMOTE_PORT(ulInboundPortKey)
+ (USHORT)CONNECTION_REMOTE_PORT(ulOutboundPortKey);
pEntry->ulProtocolChecksumDelta[NsOutboundDirection] =
(USHORT)~CONNECTION_REMOTE_PORT(ulOutboundPortKey)
+ (USHORT)CONNECTION_REMOTE_PORT(ulInboundPortKey);
if (NS_PROTOCOL_TCP == ucProtocol)
{
pEntry->PacketRoutine[NsInboundDirection] =
NsInboundTcpTranslatePortPacketRoutine;
pEntry->PacketRoutine[NsOutboundDirection] =
NsOutboundTcpTranslatePortPacketRoutine;
}
else
{
pEntry->PacketRoutine[NsInboundDirection] =
NsInboundUdpTranslatePortPacketRoutine;
pEntry->PacketRoutine[NsOutboundDirection] =
NsOutboundUdpTranslatePortPacketRoutine;
}
}
else if (NS_PROTOCOL_TCP == ucProtocol)
{
pEntry->PacketRoutine[NsInboundDirection] = NsInboundTcpPacketRoutine;
pEntry->PacketRoutine[NsOutboundDirection] = NsOutboundTcpPacketRoutine;
}
else
{
pEntry->PacketRoutine[NsInboundDirection] = NsInboundUdpPacketRoutine;
pEntry->PacketRoutine[NsOutboundDirection] = NsOutboundUdpPacketRoutine;
}
NsConnectionTree[NsInboundDirection] =
NspInsertInboundConnectionEntry(pInboundInsertionPoint, pEntry);
NsConnectionTree[NsOutboundDirection] =
NspInsertOutboundConnectionEntry(pOutboundInsertionPoint, pEntry);
InsertTailList(&NsConnectionList, &pEntry->Link);
InterlockedIncrement(&NsConnectionCount);
*ppNewEntry = pEntry;
return STATUS_SUCCESS;
} // NsCreateConnectionEntry
NTSTATUS
NsDeleteConnectionEntry(
PNS_CONNECTION_ENTRY pEntry
)
/*++
Routine Description:
Called to delete a connection entry. The initial reference to the entry
is released, so that cleanup occurs whenever the last reference is released.
Arguments:
pEntry - the connection entry to be deleted.
Return Value:
NTSTATUS - indicates success/failure.
Environment:
Invoked with 'NsConnectionLock' held by the caller.
--*/
{
PRTL_SPLAY_LINKS SLink;
TRACE(CONN_LIFETIME, ("NsDeleteConnectionEntry\n"));
ASSERT(NULL != pEntry);
if (NS_CONNECTION_DELETED(pEntry))
{
return STATUS_PENDING;
}
//
// Mark the entry as deleted so attempts to reference it
// will fail from now on.
//
pEntry->ulFlags |= NS_CONNECTION_FLAG_DELETED;
//
// Take the entry off the list and splay-trees
//
InterlockedDecrement(&NsConnectionCount);
RemoveEntryList(&pEntry->Link);
SLink = RtlDelete(&pEntry->SLink[NsInboundDirection]);
NsConnectionTree[NsInboundDirection] =
(SLink
? CONTAINING_RECORD(SLink,NS_CONNECTION_ENTRY,SLink[NsInboundDirection])
: NULL);
SLink = RtlDelete(&pEntry->SLink[NsOutboundDirection]);
NsConnectionTree[NsOutboundDirection] =
(SLink
? CONTAINING_RECORD(SLink,NS_CONNECTION_ENTRY,SLink[NsOutboundDirection])
: NULL);
//
// Clear the entry from the connection cache
//
ClearCache(
NsConnectionCache,
(ULONG)pEntry->ul64AddressKey
);
if (0 != InterlockedDecrement(&pEntry->ulReferenceCount)) {
//
// The entry is in use, defer final cleanup
//
return STATUS_PENDING;
}
//
// Go ahead with final cleanup
//
NsCleanupConnectionEntry(pEntry);
return STATUS_SUCCESS;
} // NsDeleteConnectionEntry
NTSTATUS
NsInitializeConnectionManagement(
VOID
)
/*++
Routine Description:
This routine is invoked to initialize the connection management module.
Arguments:
none.
Return Value:
NTSTATUS.
--*/
{
CALLTRACE(("NsInitializeConnectionManagement\n"));
InitializeCache(NsConnectionCache);
NsConnectionCount = 0;
InitializeListHead(&NsConnectionList);
KeInitializeSpinLock(&NsConnectionLock);
ExInitializeNPagedLookasideList(
&NsConnectionLookasideList,
NULL,
NULL,
0,
sizeof(NS_CONNECTION_ENTRY),
NS_TAG_CONNECTION,
NS_CONNECTION_LOOKASIDE_DEPTH
);
NsConnectionTree[NsInboundDirection] = NULL;
NsConnectionTree[NsOutboundDirection] = NULL;
NsNextSourcePort = NS_SOURCE_PORT_END;
return STATUS_SUCCESS;
} // NsInitializeConnectionManagement
PNS_CONNECTION_ENTRY
NsLookupInboundConnectionEntry(
ULONG64 ul64AddressKey,
ULONG ulPortKey,
UCHAR ucProtocol,
PVOID pvIpSecContext,
BOOLEAN *pfPortConflicts OPTIONAL,
PNS_CONNECTION_ENTRY *ppInsertionPoint OPTIONAL
)
/*++
Routine Description:
Called to lookup an inbound connection entry.
Arguments:
ul64AddressKey - the addressing information for the connection
ulPortKey - the port information for the connection
ucProtocol - the protocol for the connection
pvIpSecContext - the IpSec context for the connection
pfPortConflicts - on failure, receives a boolean the indicates why
the lookup failed: TRUE if the lookup failed because there is
an identical connection entry w/ different IpSec context, FALSE
otherwise.
ppInsertionPoint - receives the insertion point if not found
Return Value:
PNS_CONNECTION_ENTRY - a pointer to the connection entry, if found, or
NULL otherwise.
Environment:
Invoked with NsConnectionLock held by the caller.
--*/
{
PNS_CONNECTION_ENTRY pRoot;
PNS_CONNECTION_ENTRY pEntry;
PNS_CONNECTION_ENTRY pParent = NULL;
PRTL_SPLAY_LINKS SLink;
TRACE(
CONN_LOOKUP,
("NsLookupInboundConnectionEntry: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d : %d\n",
ucProtocol,
ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_REMOTE_PORT(ulPortKey)),
ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_LOCAL_PORT(ulPortKey)),
pvIpSecContext
));
//
// First look in the cache
//
pEntry = (PNS_CONNECTION_ENTRY)
ProbeCache(
NsConnectionCache,
(ULONG)ul64AddressKey
);
if (NULL != pEntry
&& pEntry->ul64AddressKey == ul64AddressKey
&& pEntry->ucProtocol == ucProtocol
&& pEntry->ulPortKey[NsInboundDirection] == ulPortKey
&& pEntry->pvIpSecContext == pvIpSecContext)
{
TRACE(CONN_LOOKUP, ("NsLookupInboundConnectionEntry: Cache Hit\n"));
return pEntry;
}
if (pfPortConflicts)
{
*pfPortConflicts = FALSE;
}
//
// Search the full tree. Keys are checked in the
// following order:
//
// 1. Address Key
// 2. Protocol
// 3. Inbound port key
// 4. IpSec context
//
pRoot = NsConnectionTree[NsInboundDirection];
for (SLink = (pRoot ? &pRoot->SLink[NsInboundDirection] : NULL ); SLink; )
{
pEntry =
CONTAINING_RECORD(SLink, NS_CONNECTION_ENTRY, SLink[NsInboundDirection]);
if (ul64AddressKey < pEntry->ul64AddressKey)
{
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (ul64AddressKey > pEntry->ul64AddressKey)
{
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
else if (ucProtocol < pEntry->ucProtocol)
{
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (ucProtocol > pEntry->ucProtocol)
{
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
else if (ulPortKey < pEntry->ulPortKey[NsInboundDirection])
{
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (ulPortKey > pEntry->ulPortKey[NsInboundDirection])
{
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
else if (pvIpSecContext < pEntry->pvIpSecContext)
{
//
// Everything matched w/ the exception of the IpSec
// context -- we have a port conflict.
//
if (pfPortConflicts)
{
*pfPortConflicts = TRUE;
}
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (pvIpSecContext > pEntry->pvIpSecContext)
{
//
// Everything matched w/ the exception of the IpSec
// context -- we have a port conflict.
//
if (pfPortConflicts)
{
*pfPortConflicts = TRUE;
}
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
//
// We found the entry -- update cache and return
//
UpdateCache(
NsConnectionCache,
(ULONG)ul64AddressKey,
(PVOID)pEntry
);
return pEntry;
}
//
// Not found -- provide insertion point if requested
//
if (ppInsertionPoint)
{
*ppInsertionPoint = pParent;
}
return NULL;
} // NsLookupInboundConnectionEntry
PNS_CONNECTION_ENTRY
NsLookupOutboundConnectionEntry(
ULONG64 ul64AddressKey,
ULONG ulPortKey,
UCHAR ucProtocol,
PNS_CONNECTION_ENTRY *ppInsertionPoint OPTIONAL
)
/*++
Routine Description:
Called to lookup an outbound connection entry.
Arguments:
ul64AddressKey - the addressing information for the connection
ulPortKey - the port information for the connection
ucProtocol - the protocol for the connection
ppInsertionPoint - receives the insertion point if not found
Return Value:
PNS_CONNECTION_ENTRY - a pointer to the connection entry, if found, or
NULL otherwise.
Environment:
Invoked with NsConnectionLock held by the caller.
--*/
{
PNS_CONNECTION_ENTRY pRoot;
PNS_CONNECTION_ENTRY pEntry;
PNS_CONNECTION_ENTRY pParent = NULL;
PRTL_SPLAY_LINKS SLink;
TRACE(
CONN_LOOKUP,
("NsLookupOutboundConnectionEntry: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d\n",
ucProtocol,
ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_LOCAL_PORT(ulPortKey)),
ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
NTOHS(CONNECTION_REMOTE_PORT(ulPortKey))
));
//
// First look in the cache
//
pEntry = (PNS_CONNECTION_ENTRY)
ProbeCache(
NsConnectionCache,
(ULONG)ul64AddressKey
);
if (NULL != pEntry
&& pEntry->ul64AddressKey == ul64AddressKey
&& pEntry->ucProtocol == ucProtocol
&& pEntry->ulPortKey[NsOutboundDirection] == ulPortKey)
{
TRACE(CONN_LOOKUP, ("NsLookupOutboundConnectionEntry: Cache Hit\n"));
return pEntry;
}
//
// Search the full tree. Keys are checked in the
// following order:
//
// 1. Address Key
// 2. Protocol
// 3. Outbound port key
//
pRoot = NsConnectionTree[NsOutboundDirection];
for (SLink = (pRoot ? &pRoot->SLink[NsOutboundDirection] : NULL ); SLink; )
{
pEntry =
CONTAINING_RECORD(SLink, NS_CONNECTION_ENTRY, SLink[NsOutboundDirection]);
if (ul64AddressKey < pEntry->ul64AddressKey)
{
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (ul64AddressKey > pEntry->ul64AddressKey)
{
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
else if (ucProtocol < pEntry->ucProtocol)
{
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (ucProtocol > pEntry->ucProtocol)
{
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
else if (ulPortKey < pEntry->ulPortKey[NsOutboundDirection])
{
pParent = pEntry;
SLink = RtlLeftChild(SLink);
continue;
}
else if (ulPortKey > pEntry->ulPortKey[NsOutboundDirection])
{
pParent = pEntry;
SLink = RtlRightChild(SLink);
continue;
}
//
// We found the entry -- update cache and return
//
UpdateCache(
NsConnectionCache,
(ULONG)ul64AddressKey,
(PVOID)pEntry
);
return pEntry;
}
//
// Not found -- provide insertion point if requested
//
if (ppInsertionPoint)
{
*ppInsertionPoint = pParent;
}
return NULL;
} // NsLookupOutboundConnectionEntry
PNS_CONNECTION_ENTRY
NspInsertInboundConnectionEntry(
PNS_CONNECTION_ENTRY pParent,
PNS_CONNECTION_ENTRY pEntry
)
/*++
Routine Description:
This routine inserts a connection entry into the tree.
Arguments:
pParent - the node to be the parent for the new connection entry.
If NULL, the new entry becomes the root.
pEntry - the new connection entry to be inserted.
Return Value:
PNS_CONNECTION_ENTRY - The new root of the tree.
If insertion fails, returns NULL.
Environment:
Invoked with 'NsConnectionLock' held by the caller.
--*/
{
PRTL_SPLAY_LINKS pRoot;
ASSERT(NULL != pEntry);
if (NULL == pParent)
{
//
// The new entry is to be the root.
//
return pEntry;
}
//
// Insert as left or right child. Keys are checked in the
// following order:
//
// 1. Address Key
// 2. Protocol
// 3. Inbound port key
// 4. IpSec context
//
if (pEntry->ul64AddressKey < pParent->ul64AddressKey)
{
RtlInsertAsLeftChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->ul64AddressKey > pParent->ul64AddressKey)
{
RtlInsertAsRightChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->ucProtocol < pParent->ucProtocol)
{
RtlInsertAsLeftChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->ucProtocol > pParent->ucProtocol)
{
RtlInsertAsRightChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->ulPortKey[NsInboundDirection] < pParent->ulPortKey[NsInboundDirection])
{
RtlInsertAsLeftChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->ulPortKey[NsInboundDirection] > pParent->ulPortKey[NsInboundDirection])
{
RtlInsertAsRightChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->pvIpSecContext < pParent->pvIpSecContext)
{
RtlInsertAsLeftChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else if (pEntry->pvIpSecContext > pParent->pvIpSecContext)
{
RtlInsertAsRightChild(
&pParent->SLink[NsInboundDirection],
&pEntry->SLink[NsInboundDirection]
);
}
else
{
//
// Duplicate entry -- this should not happen.
//
ASSERT(FALSE);
return NULL;
}
//
// Splay the new node and return the resulting root.
//
pRoot = RtlSplay(&pEntry->SLink[NsInboundDirection]);
return CONTAINING_RECORD(pRoot, NS_CONNECTION_ENTRY, SLink[NsInboundDirection]);
} // NspInsertInboundConnectionEntry
PNS_CONNECTION_ENTRY
NspInsertOutboundConnectionEntry(
PNS_CONNECTION_ENTRY pParent,
PNS_CONNECTION_ENTRY pEntry
)
/*++
Routine Description:
This routine inserts a connection entry into the tree.
Arguments:
pParent - the node to be the parent for the new connection entry.
If NULL, the new entry becomes the root.
pEntry - the new connection entry to be inserted.
Return Value:
PNS_CONNECTION_ENTRY - The new root of the tree.
If insertion fails, returns NULL.
Environment:
Invoked with 'NsConnectionLock' held by the caller.
--*/
{
PRTL_SPLAY_LINKS pRoot;
ASSERT(NULL != pEntry);
if (NULL == pParent)
{
//
// The new entry is to be the root.
//
return pEntry;
}
//
// Insert as left or right child. Keys are checked in the
// following order:
//
// 1. Address Key
// 2. Protocol
// 3. Outbound port key
//
if (pEntry->ul64AddressKey < pParent->ul64AddressKey)
{
RtlInsertAsLeftChild(
&pParent->SLink[NsOutboundDirection],
&pEntry->SLink[NsOutboundDirection]
);
}
else if (pEntry->ul64AddressKey > pParent->ul64AddressKey)
{
RtlInsertAsRightChild(
&pParent->SLink[NsOutboundDirection],
&pEntry->SLink[NsOutboundDirection]
);
}
else if (pEntry->ucProtocol < pParent->ucProtocol)
{
RtlInsertAsLeftChild(
&pParent->SLink[NsOutboundDirection],
&pEntry->SLink[NsOutboundDirection]
);
}
else if (pEntry->ucProtocol > pParent->ucProtocol)
{
RtlInsertAsRightChild(
&pParent->SLink[NsOutboundDirection],
&pEntry->SLink[NsOutboundDirection]
);
}
else if (pEntry->ulPortKey[NsOutboundDirection] < pParent->ulPortKey[NsOutboundDirection])
{
RtlInsertAsLeftChild(
&pParent->SLink[NsOutboundDirection],
&pEntry->SLink[NsOutboundDirection]
);
}
else if (pEntry->ulPortKey[NsOutboundDirection] > pParent->ulPortKey[NsOutboundDirection])
{
RtlInsertAsRightChild(
&pParent->SLink[NsOutboundDirection],
&pEntry->SLink[NsOutboundDirection]
);
}
else
{
//
// Duplicate entry -- this should not happen.
//
ASSERT(FALSE);
return NULL;
}
//
// Splay the new node and return the resulting root.
//
pRoot = RtlSplay(&pEntry->SLink[NsOutboundDirection]);
return CONTAINING_RECORD(pRoot, NS_CONNECTION_ENTRY, SLink[NsOutboundDirection]);
} // NspInsertOutboundConnectionEntry
VOID
NsShutdownConnectionManagement(
VOID
)
/*++
Routine Description:
This routine is invoked to shutdown the connection management module.
Arguments:
none.
Return Value:
none.
Environment:
Invoked with no references made to any connection entry.
--*/
{
KIRQL Irql;
PNS_CONNECTION_ENTRY pEntry;
CALLTRACE(("NsShutdownConnectionManagement\n"));
KeAcquireSpinLock(&NsConnectionLock, &Irql);
while (!IsListEmpty(&NsConnectionList))
{
pEntry =
CONTAINING_RECORD(
RemoveHeadList(&NsConnectionList),
NS_CONNECTION_ENTRY,
Link
);
NsCleanupConnectionEntry(pEntry);
}
NsConnectionTree[NsInboundDirection] = NULL;
NsConnectionTree[NsOutboundDirection] = NULL;
KeReleaseSpinLock(&NsConnectionLock, Irql);
ExDeleteNPagedLookasideList(&NsConnectionLookasideList);
} // NsShutdownConnectionManagement