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

639 lines
14 KiB
C

/*++
Copyright (c) 1997 - 98, Microsoft Corporation
Module Name:
rtmregn.c
Abstract:
Contains routines for managing registration
of protocol & management entities with RTM.
Author:
Chaitanya Kodeboyina (chaitk) 20-Aug-1998
Revision History:
--*/
#include "pchrtm.h"
#pragma hdrstop
DWORD
WINAPI
RtmRegisterEntity (
IN PRTM_ENTITY_INFO RtmEntityInfo,
IN PRTM_ENTITY_EXPORT_METHODS ExportMethods OPTIONAL,
IN RTM_EVENT_CALLBACK EventCallback,
IN BOOL ReserveOpaquePtr,
OUT PRTM_REGN_PROFILE RtmRegProfile,
OUT PRTM_ENTITY_HANDLE RtmRegHandle
)
/*++
Routine Description:
Registers an entity with an RTM instance for a specific address
family.
A registration handle, and a profile of the RTM instance with
with supported views, number of equal cost NHops / route etc.
is returned.
If registration is with a new instance and/or address family,
then this instance/address family is created in this process.
Arguments:
RtmEntityInfo - Information (RtmInstance, Protocol ID etc.)
for the entity that is registering here,
ExportMethods - List of methods exported by this entity,
EventCallback - Callback invoked to inform of certain events
like entity registrations, de-registrations,
ReserveOpaquePtr - Reserve a ptr in each destination or not,
RtmRegProfile - RTM parameters that the entity will use in
RTM API calls [eg: No. of equal cost NHOPs],
RtmRegHandle - Identification handle for this entity used
in all API calls until its de-registration.
Return Value:
Status of the operation
--*/
{
PINSTANCE_INFO Instance;
PADDRFAM_INFO AddrFamilyInfo;
PENTITY_INFO Entity;
DWORD Status;
CHECK_FOR_RTM_API_INITIALIZED();
TraceEnter("RtmRegisterEntity");
ACQUIRE_INSTANCES_WRITE_LOCK();
do
{
//
// Search (or create) for an instance with the input RtmInstanceId
//
Status = GetInstance(RtmEntityInfo->RtmInstanceId,
TRUE,
&Instance);
if (Status != NO_ERROR)
{
break;
}
//
// Search (or create) for an address family info with input family
//
Status = GetAddressFamily(Instance,
RtmEntityInfo->AddressFamily,
TRUE,
&AddrFamilyInfo);
if (Status != NO_ERROR)
{
break;
}
//
// Search (or create) for an entity with input protocol id, instance
//
Status = GetEntity(AddrFamilyInfo,
RtmEntityInfo->EntityId.EntityId,
TRUE,
RtmEntityInfo,
ReserveOpaquePtr,
ExportMethods,
EventCallback,
&Entity);
if (Status != NO_ERROR)
{
break;
}
//
// Collect all relevant information and build registration profile
//
RtmRegProfile->MaxNextHopsInRoute = AddrFamilyInfo->MaxNextHopsInRoute;
RtmRegProfile->MaxHandlesInEnum = AddrFamilyInfo->MaxHandlesInEnum;
RtmRegProfile->ViewsSupported = AddrFamilyInfo->ViewsSupported;
RtmRegProfile->NumberOfViews = AddrFamilyInfo->NumberOfViews;
//
// Return a handle to this entity registration block
//
*RtmRegHandle = MAKE_HANDLE_FROM_POINTER(Entity);
}
while (FALSE);
RELEASE_INSTANCES_WRITE_LOCK();
TraceLeave("RtmRegisterEntity");
return Status;
}
DWORD
WINAPI
RtmDeregisterEntity (
IN RTM_ENTITY_HANDLE RtmRegHandle
)
/*++
Routine Description:
Deregisters an entity with its RTM instance and addr family.
We assume that the entity is responsible for making sure
that once this call is made, no other RTM calls will be
made using this entity registration handle. In case such
a thing happens, it might result in crashing the process.
We make this assumption for performance reasons - else we
we have to make sure that the entity handle passed in is
valid in a try-except block (same with other handles) and
this will lead to degradation in performance.
Arguments:
RtmRegHandle - RTM registration handle for the entity
Return Value:
Status of the operation
--*/
{
PADDRFAM_INFO AddrFamInfo;
PENTITY_INFO Entity;
HANDLE Event;
DWORD Status;
TraceEnter("RtmDeregisterEntity");
VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
//
// Release all handles opened by entity
//
CleanupAfterDeregister(Entity);
//
// Mark the entity info as de-registered
//
Entity->State = ENTITY_STATE_DEREGISTERED;
//
// Make sure no more methods are invoked
//
ACQUIRE_ENTITY_METHODS_WRITE_LOCK(Entity);
// At this time all entity methods are
// done - no more methods will be called
// as we set the state to DEREGISTERED
RELEASE_ENTITY_METHODS_WRITE_LOCK(Entity);
//
// Remove from entity table and inform others
//
AddrFamInfo = Entity->OwningAddrFamily;
ACQUIRE_INSTANCES_WRITE_LOCK();
//
// Remove entity from the list of entities
// even before ref counts on this entity
// go to zero - this enables the entity to
// re-register meanwhile as a new entity.
//
RemoveEntryList(&Entity->EntityTableLE);
//
// Insert in the list of entities to be
// destroyed on the address family info.
//
InsertTailList(&AddrFamInfo->DeregdEntities,
&Entity->EntityTableLE);
InformEntitiesOfEvent(AddrFamInfo->EntityTable,
RTM_ENTITY_DEREGISTERED,
Entity);
RELEASE_INSTANCES_WRITE_LOCK();
DBG_UNREFERENCED_LOCAL_VARIABLE(Event);
#if DBG_REF
//
// Create an event on which to block on - this
// event gets signalled when entity ref is 0.
//
Event = CreateEvent(NULL, FALSE, FALSE, NULL);
ASSERT(Event != NULL);
Entity->BlockingEvent = Event;
#endif
//
// Remove the creation reference on the entity
//
DEREFERENCE_ENTITY(Entity, CREATION_REF);
DBG_UNREFERENCED_LOCAL_VARIABLE(Status);
#if DBG_REF
//
// Block until the reference count goes to zero
//
Status = WaitForSingleObject(Event, INFINITE);
ASSERT(Status == WAIT_OBJECT_0);
CloseHandle(Event);
#endif
TraceLeave("RtmDeregisterEntity");
return NO_ERROR;
}
DWORD
WINAPI
RtmGetRegisteredEntities (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN OUT PUINT NumEntities,
OUT PRTM_ENTITY_HANDLE EntityHandles,
OUT PRTM_ENTITY_INFO EntityInfos OPTIONAL
)
/*++
Routine Description:
Retrieves information about all entities registered with an
RTM instance.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NumEntities - Number of entities that can be filled
is passed in, and number of entities
that exist in this address family is retd,
RegdEntityHandles - Array to return the entity handles in,
RegdEntityInfos - Array to return the entity infos in
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
PADDRFAM_INFO AddrFamilyInfo;
USHORT RtmInstanceId;
USHORT AddressFamily;
UINT EntitiesCopied;
UINT i;
PLIST_ENTRY Entities;
PLIST_ENTRY p;
DWORD Status;
TraceEnter("RtmGetRegisteredEntities");
VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
AddrFamilyInfo = Entity->OwningAddrFamily;
//
// Just cache the instance and address family
// as it is identical for all entities infos.
//
#if WRN
RtmInstanceId = AddressFamily = 0;
#endif
if (ARGUMENT_PRESENT(EntityInfos))
{
RtmInstanceId = AddrFamilyInfo->Instance->RtmInstanceId;
AddressFamily = AddrFamilyInfo->AddressFamily;
}
//
// Go over the entity table and copy out handles
// If the OPTIONAL argument 'EntityInfos' is
// given, copy out entity information as well.
//
EntitiesCopied = 0;
ACQUIRE_INSTANCES_READ_LOCK();
for (i = 0; (i < ENTITY_TABLE_SIZE) && (EntitiesCopied < *NumEntities);i++)
{
Entities = &AddrFamilyInfo->EntityTable[i];
//
// Process the next bucket in the entities table
//
for (p = Entities->Flink; p != Entities; p = p->Flink)
{
Entity = CONTAINING_RECORD(p, ENTITY_INFO, EntityTableLE);
//
// Copy the next entity handle and info to output buffer
//
if (Entity->State != ENTITY_STATE_DEREGISTERED)
{
EntityHandles[EntitiesCopied]=MAKE_HANDLE_FROM_POINTER(Entity);
REFERENCE_ENTITY(Entity, HANDLE_REF);
if (ARGUMENT_PRESENT(EntityInfos))
{
EntityInfos[EntitiesCopied].RtmInstanceId = RtmInstanceId;
EntityInfos[EntitiesCopied].AddressFamily = AddressFamily;
EntityInfos[EntitiesCopied].EntityId = Entity->EntityId;
}
if (++EntitiesCopied == *NumEntities)
{
break;
}
}
}
}
//
// Set output to total entities present,
// and also the appropriate return value
//
if (*NumEntities >= AddrFamilyInfo->NumEntities)
{
Status = NO_ERROR;
}
else
{
Status = ERROR_INSUFFICIENT_BUFFER;
}
*NumEntities = AddrFamilyInfo->NumEntities;
RELEASE_INSTANCES_READ_LOCK();
TraceLeave("RtmGetRegisteredEntities");
return Status;
}
DWORD
WINAPI
RtmReleaseEntities (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN UINT NumEntities,
IN PRTM_ENTITY_HANDLE EntityHandles
)
/*++
Routine Description:
Release (also called de-reference) handles to entities
obtained in other RTM calls.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
NumEntities - Number of handles that are being released,
EntityHandles - An array of handles that are being released.
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
UINT i;
DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
//
// Dereference each entity handle in array
//
for (i = 0; i < NumEntities; i++)
{
Entity = ENTITY_FROM_HANDLE(EntityHandles[i]);
DEREFERENCE_ENTITY(Entity, HANDLE_REF);
}
return NO_ERROR;
}
DWORD
WINAPI
RtmLockDestination(
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN RTM_DEST_HANDLE DestHandle,
IN BOOL Exclusive,
IN BOOL LockDest
)
/*++
Routine Description:
Locks/unlocks a destination in the route table. This function
is used to guard the dest while opaque ptrs are being changed.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
DestHandle - Handle to the destination to be locked,
Exclusive - TRUE to lock in write mode, else read mode,
LockDest - Flag that tells whether to lock or unlock.
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
PDEST_INFO Dest;
DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
VALIDATE_DEST_HANDLE(DestHandle, &Dest);
// Lock or unlock the dest as the case may be
if (LockDest)
{
if (Exclusive)
{
ACQUIRE_DEST_WRITE_LOCK(Dest);
}
else
{
ACQUIRE_DEST_READ_LOCK(Dest);
}
}
else
{
if (Exclusive)
{
RELEASE_DEST_WRITE_LOCK(Dest);
}
else
{
RELEASE_DEST_READ_LOCK(Dest);
}
}
return NO_ERROR;
}
DWORD
WINAPI
RtmGetOpaqueInformationPointer (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN RTM_DEST_HANDLE DestHandle,
OUT PVOID *OpaqueInfoPtr
)
/*++
Routine Description:
Retrieves a pointer to the opaque info pointer field in a dest
for this entity, or NULL if entity has not reserved such a ptr
during registration.
Arguments:
RtmRegHandle - RTM registration handle for calling entity,
DestHandle - Handle to dest whose opaque info ptr we want,
OpaqueInfoPtr - Pointer to opaque info ptr is returned here
Return Value:
Status of the operation
--*/
{
PENTITY_INFO Entity;
PDEST_INFO Dest;
DWORD Status;
TraceEnter("RtmGetOpaqueInformationPointer");
*OpaqueInfoPtr = NULL;
VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
Status = ERROR_NOT_FOUND;
//
// If dest is valid and we have an opaque slot
// reserved, do ptr arithmetic to get the addr
//
if (Entity->OpaquePtrOffset != (-1))
{
//
// We do not check if the dest in deleted
// as the entity will need to access its
// opaque info even after dest is deleted.
//
Dest = DEST_FROM_HANDLE(DestHandle);
if (Dest)
{
*OpaqueInfoPtr = &Dest->OpaqueInfoPtrs[Entity->OpaquePtrOffset];
Status = NO_ERROR;
}
else
{
Status = ERROR_INVALID_HANDLE;
}
}
TraceLeave("RtmGetOpaqueInformationPointer");
return Status;
}