707 lines
16 KiB
C
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;
|
|
}
|