windows-nt/Source/XPSP1/NT/net/rras/rtmv2/rtmnhop.c
2020-09-26 16:20:57 +08:00

707 lines
16 KiB
C

/*++
Copyright (c) 1997 - 98, Microsoft Corporation
Module Name:
rtmnhop.c
Abstract:
Contains routines for managing RTM Next Hops.
Author:
Chaitanya Kodeboyina (chaitk) 21-Aug-1998
Revision History:
--*/
#include "pchrtm.h"
#pragma hdrstop
DWORD
WINAPI
RtmAddNextHop (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN PRTM_NEXTHOP_INFO NextHopInfo,
IN OUT PRTM_NEXTHOP_HANDLE NextHopHandle OPTIONAL,
OUT PRTM_NEXTHOP_CHANGE_FLAGS ChangeFlags
)
/*++
Adds or Updates a next hop entry to the entity's next-hop table.
If the 'nexthop handle' argument is present, then this next-hop
is updated. Otherwise a search is made for the address in the
input 'nexthop info', and if a next-hop is found, it is updated.
If no matching next-hop is found, the a new next-hop is added.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NextHopInfo - Info that corresponds to this next-hop,
NextHopHandle - Handle to the next-hop to update is passed
in (or NULL), and if a next-hop is created
a handle to this new next-hop is returned.
ChangeFlags - Flags whether this was a add or an update.
Return Value:
Status of the operation
--*/
{
PRTM_NET_ADDRESS NextHopAddress;
PENTITY_INFO Entity;
PDEST_INFO Dest;
PNEXTHOP_LIST NewHopList;
PNEXTHOP_INFO NewNextHop;
PNEXTHOP_INFO NextHop;
LOOKUP_CONTEXT Context;
PLIST_ENTRY p;
DWORD Status;
//
// Validate incoming information before attempting an add
//
VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
if (NextHopInfo->RemoteNextHop)
{
VALIDATE_DEST_HANDLE(NextHopInfo->RemoteNextHop, &Dest);
}
//
// If there is a next hop handle, we can avoid a search
//
NextHop = NULL;
if (ARGUMENT_PRESENT(NextHopHandle) && (*NextHopHandle))
{
VALIDATE_NEXTHOP_HANDLE(*NextHopHandle, &NextHop);
// Make sure that the caller owns this nexthop
if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
{
return ERROR_ACCESS_DENIED;
}
}
#if WRN
NewNextHop = NULL;
NewHopList = NULL;
#endif
*ChangeFlags = 0;
ACQUIRE_NHOP_TABLE_WRITE_LOCK(Entity);
do
{
//
// Search for the next hop if we don't already have one
//
if (NextHop == NULL)
{
Status = FindNextHop(Entity, NextHopInfo, &Context, &p);
if (SUCCESS(Status))
{
// The next hop already exists in the tree
NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
}
else
{
// Init new allocations in case we fail in between
NewNextHop = NULL;
NewHopList = NULL;
//
// Create a new next hop with the input information
//
Status = CreateNextHop(Entity, NextHopInfo, &NewNextHop);
if (!SUCCESS(Status))
{
break;
}
//
// Do we need to create a new list of next hops too ?
//
if (p == NULL)
{
NewHopList = AllocNZeroMemory(sizeof(NEXTHOP_LIST));
if (NewHopList == NULL)
{
break;
}
InitializeListHead(&NewHopList->NextHopsList);
// Insert the next-hop-list into the tree
NextHopAddress = &NextHopInfo->NextHopAddress;
Status = InsertIntoTable(Entity->NextHopTable,
NextHopAddress->NumBits,
NextHopAddress->AddrBits,
&Context,
&NewHopList->LookupLinkage);
if (!SUCCESS(Status))
{
break;
}
p = &NewHopList->NextHopsList;
}
// Insert the next hop in the list and ref it
InsertTailList(p, &NewNextHop->NextHopsLE);
Entity->NumNextHops++;
NextHop = NewNextHop;
*ChangeFlags = RTM_NEXTHOP_CHANGE_NEW;
}
}
//
// If this is an update, copy necessary information
//
if (*ChangeFlags != RTM_NEXTHOP_CHANGE_NEW)
{
CopyToNextHop(Entity, NextHopInfo, NextHop);
}
//
// Return the next hop handle if not passed in
//
if (ARGUMENT_PRESENT(NextHopHandle))
{
if (*NextHopHandle == NULL)
{
*NextHopHandle = MAKE_HANDLE_FROM_POINTER(NextHop);
REFERENCE_NEXTHOP(NextHop, HANDLE_REF);
}
}
Status = NO_ERROR;
}
while(FALSE);
RELEASE_NHOP_TABLE_WRITE_LOCK(Entity);
if (!SUCCESS(Status))
{
// Some error occured - clean up
if (NewHopList)
{
FreeMemory(NewHopList);
}
if (NewNextHop)
{
DEREFERENCE_NEXTHOP(NewNextHop, CREATION_REF);
}
}
return Status;
}
DWORD
WINAPI
RtmDeleteNextHop (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN RTM_NEXTHOP_HANDLE NextHopHandle OPTIONAL,
IN PRTM_NEXTHOP_INFO NextHopInfo
)
/*++
Routine Description:
Deletes a next hop from the next-hop table. The next-hop
memory remains in use until all reference counts go to 0.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NextHopHandle - Handle to the next-hop we want to delete,
NextHopInfo - If no NextHopHandle is passed in, this is
used to match the next-hop to be deleted.
Return Value:
Status of the operation
--*/
{
PRTM_NET_ADDRESS NextHopAddress;
PLOOKUP_LINKAGE Linkage;
PENTITY_INFO Entity;
PNEXTHOP_LIST HopList;
PNEXTHOP_INFO NextHop;
PLOOKUP_CONTEXT PContext;
LOOKUP_CONTEXT Context;
PLIST_ENTRY p;
DWORD Status;
VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
//
// If there is a next hop handle, we can avoid a search
//
NextHop = NULL;
if (ARGUMENT_PRESENT(NextHopHandle))
{
VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);
// Make sure that the caller owns this nexthop
if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
{
return ERROR_ACCESS_DENIED;
}
}
#if WRN
Status = ERROR_GEN_FAILURE;
#endif
ACQUIRE_NHOP_TABLE_WRITE_LOCK(Entity);
do
{
//
// Search for the next hop if we don't already have one
//
if (NextHop == NULL)
{
Status = FindNextHop(Entity,
NextHopInfo,
&Context,
&p);
if (!SUCCESS(Status))
{
break;
}
PContext = &Context;
NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
}
else
{
// Make sure that it has not already been deleted
if (NextHop->NextHopInfo.State == RTM_NEXTHOP_STATE_DELETED)
{
break;
}
PContext = NULL;
}
// Get a 'possible' list entry that starts the hop list
HopList = CONTAINING_RECORD(NextHop->NextHopsLE.Blink,
NEXTHOP_LIST,
NextHopsList);
// Delete this next-hop from the nexthops list
NextHop->NextHopInfo.State = RTM_NEXTHOP_STATE_DELETED;
RemoveEntryList(&NextHop->NextHopsLE);
// Do we have any more next hops on this list
if (IsListEmpty(&HopList->NextHopsList))
{
// Remove the hop-list from the next hop table
NextHopAddress = &NextHop->NextHopInfo.NextHopAddress;
Status = DeleteFromTable(Entity->NextHopTable,
NextHopAddress->NumBits,
NextHopAddress->AddrBits,
PContext,
&Linkage);
ASSERT(SUCCESS(Status) && (&HopList->LookupLinkage == Linkage));
FreeMemory(HopList);
}
// Dereference the next-hop that was deleted
Entity->NumNextHops--;
DEREFERENCE_NEXTHOP(NextHop, CREATION_REF);
if (ARGUMENT_PRESENT(NextHopHandle))
{
DEREFERENCE_NEXTHOP(NextHop, HANDLE_REF);
}
Status = NO_ERROR;
}
while (FALSE);
RELEASE_NHOP_TABLE_WRITE_LOCK(Entity);
return Status;
}
DWORD
WINAPI
RtmFindNextHop (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN PRTM_NEXTHOP_INFO NextHopInfo,
OUT PRTM_NEXTHOP_HANDLE NextHopHandle,
OUT PRTM_NEXTHOP_INFO *NextHopPointer OPTIONAL
)
/*++
Routine Description:
Finds a next hop, given its info, in entity's next-hop table.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NextHopInfo - Info for the next-hop we are searching for
( NextHopOwner, NextHopAddress, IfIndex ),
NextHopHandle - Handle to next-hop is returned (if found),
NextHopPointer - A pointer to the next-hop is returned for
fast direct access by the next-hop's owner.
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
PNEXTHOP_INFO NextHop;
PLIST_ENTRY p;
DWORD Status;
DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
VALIDATE_ENTITY_HANDLE(NextHopInfo->NextHopOwner, &Entity);
if (ARGUMENT_PRESENT(NextHopPointer))
{
// Only the nexthop owner gets a direct ptr
if (RtmRegHandle != NextHopInfo->NextHopOwner)
{
return ERROR_ACCESS_DENIED;
}
}
//
// Search for the next hop in the next hop table
//
ACQUIRE_NHOP_TABLE_READ_LOCK(Entity);
Status = FindNextHop(Entity, NextHopInfo, NULL, &p);
if (SUCCESS(Status))
{
NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
*NextHopHandle = MAKE_HANDLE_FROM_POINTER(NextHop);
REFERENCE_NEXTHOP(NextHop, HANDLE_REF);
if (ARGUMENT_PRESENT(NextHopPointer))
{
*NextHopPointer = &NextHop->NextHopInfo;
}
}
RELEASE_NHOP_TABLE_READ_LOCK(Entity);
return Status;
}
DWORD
FindNextHop (
IN PENTITY_INFO Entity,
IN PRTM_NEXTHOP_INFO NextHopInfo,
OUT PLOOKUP_CONTEXT Context OPTIONAL,
OUT PLIST_ENTRY *NextHopLE
)
/*++
Routine Description:
Finds a next hop, given its info, in entity's next-hop table.
This is a helper function that is called by public functions
that add, delete or find a next hop in the next hop table.
Arguments:
Entity - Entity whose nexthop table we are searching,
NextHopInfo - Info for the next-hop we are searching for
( NextHopOwner, NextHopAddress, IfIndex ),
Context - Search context for holding list of nexthops,
NextHopLE - List entry for the matching nexthop (if found)
(or) list entry before which it'll be inserted.
Return Value:
Status of the operation
--*/
{
PRTM_NET_ADDRESS NextHopAddress;
PNEXTHOP_LIST NextHopsList;
PNEXTHOP_INFO NextHop;
ULONG IfIndex;
PLOOKUP_LINKAGE Linkage;
PLIST_ENTRY NextHops, p;
DWORD Status;
*NextHopLE = NULL;
//
// Search for list of next hops, given the address
//
NextHopAddress = &NextHopInfo->NextHopAddress;
Status = SearchInTable(Entity->NextHopTable,
NextHopAddress->NumBits,
NextHopAddress->AddrBits,
Context,
&Linkage);
if (!SUCCESS(Status))
{
return Status;
}
NextHopsList = CONTAINING_RECORD(Linkage, NEXTHOP_LIST, LookupLinkage);
//
// Search for the nexthop with the interface idx
//
IfIndex = NextHopInfo->InterfaceIndex;
NextHops = &NextHopsList->NextHopsList;
#if WRN
NextHop = NULL;
#endif
for (p = NextHops->Flink; p != NextHops; p = p->Flink)
{
NextHop = CONTAINING_RECORD(p, NEXTHOP_INFO, NextHopsLE);
if (NextHop->NextHopInfo.InterfaceIndex <= IfIndex)
{
break;
}
}
*NextHopLE = p;
if ((p == NextHops) || (NextHop->NextHopInfo.InterfaceIndex != IfIndex))
{
return ERROR_NOT_FOUND;
}
return NO_ERROR;
}
DWORD
WINAPI
RtmGetNextHopPointer (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN RTM_NEXTHOP_HANDLE NextHopHandle,
OUT PRTM_NEXTHOP_INFO *NextHopPointer
)
/*++
Routine Description:
Gets a direct pointer to the next-hop for read/write by its owner.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NextHopHandle - Handle to the next-hop whose pointer we want,
NextHopPointer - A pointer to the next-hop is returned for
fast direct access by the caller, only if
the caller is the owner of this next-hop.
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
PNEXTHOP_INFO NextHop;
DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);
//
// Return a pointer only if caller owns next-hop
//
if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
{
return ERROR_ACCESS_DENIED;
}
*NextHopPointer = &NextHop->NextHopInfo;
return NO_ERROR;
}
DWORD
WINAPI
RtmLockNextHop(
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN RTM_NEXTHOP_HANDLE NextHopHandle,
IN BOOL Exclusive,
IN BOOL LockNextHop,
OUT PRTM_NEXTHOP_INFO *NextHopPointer OPTIONAL
)
/*++
Routine Description:
Locks or Unlocks a next hop. This function is called by the
next-hop's owner to lock the next-hop before making changes
directly to the next-hop using a pointer to this next-hop.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NextHopHandle - Handle to the next-hop that we want to lock,
Exclusive - TRUE to lock in write mode, else read mode,
LockNextHop - Lock nexthop if TRUE, Unlock it if FALSE,
NextHopPointer - A pointer to the next-hop is returned for
fast direct access by the next hop's owner.
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
PNEXTHOP_INFO NextHop;
VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);
//
// Lock or unlock only if caller owns next-hop
//
if (NextHop->NextHopInfo.NextHopOwner != RtmRegHandle)
{
return ERROR_ACCESS_DENIED;
}
// Return a direct pointer for use in update
if (ARGUMENT_PRESENT(NextHopPointer))
{
*NextHopPointer = &NextHop->NextHopInfo;
}
// Lock or unlock the nexthop as the case may be
if (LockNextHop)
{
if (Exclusive)
{
ACQUIRE_NHOP_TABLE_WRITE_LOCK(Entity);
}
else
{
ACQUIRE_NHOP_TABLE_READ_LOCK(Entity);
}
}
else
{
if (Exclusive)
{
RELEASE_NHOP_TABLE_WRITE_LOCK(Entity);
}
else
{
RELEASE_NHOP_TABLE_READ_LOCK(Entity);
}
}
return NO_ERROR;
}