/*++

Copyright (c) 1997 - 98, Microsoft Corporation

Module Name:

    rtminfo.c

Abstract:

    Contains routines for getting information
    on various objects pointed to by handles.

Author:

    Chaitanya Kodeboyina (chaitk)  22-Aug-1998

Revision History:

--*/

#include "pchrtm.h"

#pragma hdrstop


DWORD
WINAPI
RtmGetEntityInfo (
    IN      RTM_ENTITY_HANDLE               RtmRegHandle,
    IN      RTM_ENTITY_HANDLE               EntityHandle,
    OUT     PRTM_ENTITY_INFO                EntityInfo
    )

/*++

Routine Description:

    Retrieves information pertaining to a registered entity.

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    EntityHandle      - RTM handle for entity whose info we want,

    EntityInfo        - Block in which the entity info is returned.

Return Value:

    Status of the operation

--*/

{
    PADDRFAM_INFO    AddrFamilyInfo;
    PENTITY_INFO     Entity;

    DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

    VALIDATE_ENTITY_HANDLE(EntityHandle, &Entity);

    //
    // Copy the entity information to output buffer
    //

    AddrFamilyInfo = Entity->OwningAddrFamily;

    EntityInfo->RtmInstanceId = AddrFamilyInfo->Instance->RtmInstanceId;

    EntityInfo->AddressFamily = AddrFamilyInfo->AddressFamily;

    EntityInfo->EntityId = Entity->EntityId;

    return NO_ERROR;
}


DWORD
WINAPI
RtmGetDestInfo (
    IN      RTM_ENTITY_HANDLE               RtmRegHandle,
    IN      RTM_DEST_HANDLE                 DestHandle,
    IN      ULONG                           ProtocolId,
    IN      RTM_VIEW_SET                    TargetViews,
    OUT     PRTM_DEST_INFO                  DestInfo
    )

/*++

Routine Description:

    Retrieves information for a destination in the route table

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    DestHandle        - RTM handle for dest whose info we want,

    ProtocolId        - Protocol whose best route info is retd,

    TargetViews       - Views in which best route info is retd,

    DestInfo          - Block in which the dest info is returned.

Return Value:

    Status of the operation

--*/

{
    PENTITY_INFO     Entity;
    PDEST_INFO       Dest;

    VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

    // VALIDATE_DEST_HANDLE(DestHandle, &Dest);
    Dest = DEST_FROM_HANDLE(DestHandle);
    if (!Dest)
    {
        return ERROR_INVALID_HANDLE;
    }

    ACQUIRE_DEST_READ_LOCK(Dest);

    GetDestInfo(Entity, 
                Dest, 
                ProtocolId,
                TargetViews,
                DestInfo);

    RELEASE_DEST_READ_LOCK(Dest);

    return NO_ERROR;
}


VOID
GetDestInfo (
    IN      PENTITY_INFO                    Entity,
    IN      PDEST_INFO                      Dest,
    IN      ULONG                           ProtocolId,
    IN      RTM_VIEW_SET                    TargetViews,
    OUT     PRTM_DEST_INFO                  DestInfo
)

/*++

Routine Description:

    Retrieves information for a destination in the route table

Arguments:

    Entity            - RTM registration info for calling entity,

    Dest              - Pointer to the dest whose info we want,

    ProtocolId        - Protocol whose best route info is retd,

    TargetViews       - Views in which best route info is retd,

    DestInfo          - Block in which the dest info is returned.

Return Value:

    None

--*/

{
    PENTITY_INFO     Owner;
    PROUTE_INFO      Route;
    RTM_VIEW_SET     ViewsSeen;
    RTM_VIEW_SET     ViewSet;
    RTM_VIEW_SET     BelongsToViews;
    PLIST_ENTRY      p;
    UINT             i, j, k;

    // Limit caller's interest to set of views supported
    TargetViews &= Entity->OwningAddrFamily->ViewsSupported;

    //
    // Copy dest info to output and ref handles given out
    //

    DestInfo->DestHandle = MAKE_HANDLE_FROM_POINTER(Dest);

    REFERENCE_DEST(Dest, HANDLE_REF);

    CopyMemory(&DestInfo->DestAddress,
               &Dest->DestAddress,
               sizeof(RTM_NET_ADDRESS));

    DestInfo->LastChanged = Dest->LastChanged;

    DestInfo->BelongsToViews = Dest->BelongsToViews;

    //
    // Copy the holddown route out in all requested views
    //

    ViewSet = TargetViews;
    
    for (i = j = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
    {
        if (ViewSet & 0x01)
        {
            k = Entity->OwningAddrFamily->ViewIndexFromId[i];

            Route = Dest->ViewInfo[k].HoldRoute;

            //
            // Init view info and fill the holddown route
            //

            ZeroMemory(&DestInfo->ViewInfo[j], sizeof(DestInfo->ViewInfo[0]));

            DestInfo->ViewInfo[j].ViewId = i;

            if (Route)
            {
                DestInfo->ViewInfo[j].HoldRoute = 
                            MAKE_HANDLE_FROM_POINTER(Route);

                REFERENCE_ROUTE(Route, HANDLE_REF);
            }

            j++;
        }

        ViewSet >>= 1;
    }

    // Keep track of total number of view info slots filled in
    DestInfo->NumberOfViews = j;

    //
    // Fill up information in all the views he is interested in
    //

    if (TargetViews & Dest->BelongsToViews)
    {
        // Resolve the protocol id if it is RTM_THIS_PROTOCOL

        if (ProtocolId == RTM_THIS_PROTOCOL)
        {
            ProtocolId = Entity->EntityId.EntityProtocolId;
        }

        ViewsSeen = 0;

        //
        // Copy best route in each view & ref handles given out
        //

        for (p = Dest->RouteList.Flink; p != &Dest->RouteList; p = p->Flink)
        {
            Route = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);

            //
            // Make sure that this agrees with our protocol id
            //

            Owner = ENTITY_FROM_HANDLE(Route->RouteInfo.RouteOwner);

            if (ProtocolId != RTM_BEST_PROTOCOL)
            {
                if (Owner->EntityId.EntityProtocolId != ProtocolId)
                {
                    continue;
                }
            }   

            //
            // Does this route belong to any interested views
            //

            if ((TargetViews & Route->RouteInfo.BelongsToViews) == 0)
            {
                continue;
            }

            //
            // Update dest info in each view that route belongs to
            //

            BelongsToViews = Route->RouteInfo.BelongsToViews;

            ViewSet = TargetViews;

            for (i = j = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
            {
                if (ViewSet & 0x01)
                {
                    if (BelongsToViews & 0x01)
                    {
                        //
                        // Increment number of routes in this view
                        //

                        DestInfo->ViewInfo[j].NumRoutes++;

                        //
                        // If you not already seen this view (in
                        // other words got the best route in it)
                        // update the DestInfo for this view now
                        //

                        if (!(ViewsSeen & VIEW_MASK(i)))
                        {
                            DestInfo->ViewInfo[j].Route = 
                                    MAKE_HANDLE_FROM_POINTER(Route);

                            REFERENCE_ROUTE(Route, HANDLE_REF);


                            DestInfo->ViewInfo[j].Owner = 
                                    MAKE_HANDLE_FROM_POINTER(Owner);

                            REFERENCE_ENTITY(Owner, HANDLE_REF);


                            DestInfo->ViewInfo[j].DestFlags = 
                                            Route->RouteInfo.Flags;
                        }
                    }

                    j++;
                }

                ViewSet >>= 1;

                BelongsToViews >>= 1;
            }

            ViewsSeen |= Route->RouteInfo.BelongsToViews;
        }
    }

    return;
}


DWORD
WINAPI
RtmGetRouteInfo (
    IN      RTM_ENTITY_HANDLE               RtmRegHandle,
    IN      RTM_ROUTE_HANDLE                RouteHandle,
    OUT     PRTM_ROUTE_INFO                 RouteInfo   OPTIONAL,
    OUT     PRTM_NET_ADDRESS                DestAddress OPTIONAL
    )

/*++

Routine Description:

    Retrieves information for a route in the route table

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    RouteHandle       - RTM handle for route whose info we want,

    RouteInfo         - Block in which the route info is returned.

Return Value:

    Status of the operation

--*/

{
    PENTITY_INFO     Entity;
    PROUTE_INFO      Route;
    PDEST_INFO       Dest;

    DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

#if 1
    Route = ROUTE_FROM_HANDLE(RouteHandle);                         

    if (!Route)
    {                                                               
        return ERROR_INVALID_HANDLE;                                
    }                                                               

#else
    VALIDATE_ROUTE_HANDLE(RouteHandle, &Route);
#endif

    Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);

    // Get a consitent picture of the route

    ACQUIRE_DEST_READ_LOCK(Dest);

    if (ARGUMENT_PRESENT(RouteInfo))
    {
        GetRouteInfo(Dest, Route, RouteInfo);
    }

    RELEASE_DEST_READ_LOCK(Dest);

    // No lock reqd - dest addr is constant

    if (ARGUMENT_PRESENT(DestAddress))
    {
        CopyMemory(DestAddress, &Dest->DestAddress, sizeof(RTM_NET_ADDRESS));
    }

    return NO_ERROR;
}


VOID
WINAPI
GetRouteInfo (
    IN      PDEST_INFO                      Dest,
    IN      PROUTE_INFO                     Route,
    OUT     PRTM_ROUTE_INFO                 RouteInfo
    )

/*++

Routine Description:

    Retrieves information for a route in the route table

Arguments:

    Dest              - Pointer to the destination of the route,

    Route             - Pointer to the route whose info we want,

    RouteInfo         - Block in which the route info is returned.

Return Value:

    None

--*/

{
    PENTITY_INFO     Entity;
    PNEXTHOP_INFO    Neighbour;
    PNEXTHOP_INFO    NextHop;
    UINT             NumBytes;
    UINT             i;

    //
    // Copy the route information to output buffer
    //

    NumBytes = sizeof(RTM_ROUTE_INFO) + 
                    sizeof(RTM_NEXTHOP_HANDLE) *
                        (Route->RouteInfo.NextHopsList.NumNextHops - 1);

    CopyMemory(RouteInfo, &Route->RouteInfo, NumBytes);

    //
    // Reference handles that are given out in info
    //

    Entity = ENTITY_FROM_HANDLE(RouteInfo->RouteOwner);
    REFERENCE_ENTITY(Entity, HANDLE_REF);

    if (RouteInfo->Neighbour)
    {
        Neighbour = NEXTHOP_FROM_HANDLE(RouteInfo->Neighbour);
        REFERENCE_NEXTHOP(Neighbour, HANDLE_REF);
    }

    for (i = 0; i < RouteInfo->NextHopsList.NumNextHops; i++)
    {
        NextHop = NEXTHOP_FROM_HANDLE(RouteInfo->NextHopsList.NextHops[i]);
        REFERENCE_NEXTHOP(NextHop, HANDLE_REF);
    }

    REFERENCE_DEST(Dest, HANDLE_REF);

    return;
}


DWORD
WINAPI
RtmGetNextHopInfo (
    IN      RTM_ENTITY_HANDLE               RtmRegHandle,
    IN      RTM_NEXTHOP_HANDLE              NextHopHandle,
    OUT     PRTM_NEXTHOP_INFO               NextHopInfo
    )

/*++

Routine Description:

    Retrieves information for a next-hop in the route table

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    NextHopHandle     - RTM handle for next-hop whose info we want,

    NextHopInfo       - Block in which the next-hop info is returned.

Return Value:

    Status of the operation

--*/

{
    PENTITY_INFO     Entity;
    PNEXTHOP_INFO    NextHop;
    PDEST_INFO       Dest;

    DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

    VALIDATE_NEXTHOP_HANDLE(NextHopHandle, &NextHop);

    Entity = ENTITY_FROM_HANDLE(NextHop->NextHopInfo.NextHopOwner);

    ACQUIRE_NHOP_TABLE_READ_LOCK(Entity);

    //
    // Copy the next-hop information to output buffer
    //

    CopyMemory(NextHopInfo, &NextHop->NextHopInfo, sizeof(RTM_NEXTHOP_INFO));

    //
    // Reference handles that are given out in info
    //

    if (NextHop->NextHopInfo.RemoteNextHop)
    {
        Dest = DEST_FROM_HANDLE(NextHop->NextHopInfo.RemoteNextHop);
        REFERENCE_DEST(Dest, HANDLE_REF);
    }

    REFERENCE_ENTITY(Entity, HANDLE_REF);

    RELEASE_NHOP_TABLE_READ_LOCK(Entity);

    return NO_ERROR;
}


DWORD
WINAPI
RtmReleaseEntityInfo (
    IN      RTM_ENTITY_HANDLE              RtmRegHandle,
    IN      PRTM_ENTITY_INFO               EntityInfo
    )

/*++

Routine Description:

    Releases all handles present in the input info structure

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    EntityInfo        - All handles in this info are de-referenced.

Return Value:

    Status of the operation

--*/

{
    UNREFERENCED_PARAMETER(RtmRegHandle);
    UNREFERENCED_PARAMETER(EntityInfo);

    return NO_ERROR;
}


DWORD
WINAPI
RtmReleaseDestInfo (
    IN      RTM_ENTITY_HANDLE              RtmRegHandle,
    IN      PRTM_DEST_INFO                 DestInfo
    )

/*++

Routine Description:

    Releases all handles present in the input info structure

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    DestInfo          - All handles in this info are de-referenced.

Return Value:

    Status of the operation

--*/

{
    PENTITY_INFO     Entity;
    PENTITY_INFO     Owner;
    PDEST_INFO       Dest;
    PROUTE_INFO      Route;
    UINT             i;

    DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

    for (i = 0; i < DestInfo->NumberOfViews; i++)
    {
        //
        // If a best route, dereference it and its owner
        //

        if (DestInfo->ViewInfo[i].Route)
        {
            Route = ROUTE_FROM_HANDLE(DestInfo->ViewInfo[i].Route);
            DEREFERENCE_ROUTE(Route, HANDLE_REF);

            Owner = ENTITY_FROM_HANDLE(DestInfo->ViewInfo[i].Owner);
            DEREFERENCE_ENTITY(Owner, HANDLE_REF);
        }

        //
        // If we have a holddown route, dereference it
        //

        if (DestInfo->ViewInfo[i].HoldRoute)
        {
            Route = ROUTE_FROM_HANDLE(DestInfo->ViewInfo[i].HoldRoute);
            DEREFERENCE_ROUTE(Route, HANDLE_REF);
        }
    }

    Dest = DEST_FROM_HANDLE(DestInfo->DestHandle);
    DEREFERENCE_DEST(Dest, HANDLE_REF);

    return NO_ERROR;
}


DWORD
WINAPI
RtmReleaseRouteInfo (
    IN      RTM_ENTITY_HANDLE              RtmRegHandle,
    IN      PRTM_ROUTE_INFO                RouteInfo
    )

/*++

Routine Description:

    Releases all handles present in the input info structure

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    RouteInfo         - All handles in this info are de-referenced.

Return Value:

    Status of the operation

--*/

{
    PENTITY_INFO     Entity;
    PDEST_INFO       Dest;
    PNEXTHOP_INFO    Neighbour;
    PNEXTHOP_INFO    NextHop;
    UINT             i;

    DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

    for (i = 0; i < RouteInfo->NextHopsList.NumNextHops; i++)
    {
        NextHop = NEXTHOP_FROM_HANDLE(RouteInfo->NextHopsList.NextHops[i]);
        DEREFERENCE_NEXTHOP(NextHop, HANDLE_REF);
    }

    if (RouteInfo->Neighbour)
    {
        Neighbour = NEXTHOP_FROM_HANDLE(RouteInfo->Neighbour);
        DEREFERENCE_NEXTHOP(Neighbour, HANDLE_REF);
    }

    Entity = ENTITY_FROM_HANDLE(RouteInfo->RouteOwner);
    DEREFERENCE_ENTITY(Entity, HANDLE_REF);

    Dest = DEST_FROM_HANDLE(RouteInfo->DestHandle);
    DEREFERENCE_DEST(Dest, HANDLE_REF);

    return NO_ERROR;
}


DWORD
WINAPI
RtmReleaseNextHopInfo (
    IN      RTM_ENTITY_HANDLE              RtmRegHandle,
    IN      PRTM_NEXTHOP_INFO              NextHopInfo
    )
    
/*++

Routine Description:

    Releases all handles present in the input info structure

Arguments:

    RtmRegHandle      - RTM registration handle for calling entity,

    NextHopInfo       - All handles in this info are de-referenced.

Return Value:

    Status of the operation

--*/

{
    PENTITY_INFO     Entity;
    PDEST_INFO       Dest;

    DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);

    if (NextHopInfo->RemoteNextHop)
    {
        Dest = DEST_FROM_HANDLE(NextHopInfo->RemoteNextHop);

        if (Dest)
        {
            DEREFERENCE_DEST(Dest, HANDLE_REF);
        }
    }

    Entity = ENTITY_FROM_HANDLE(NextHopInfo->NextHopOwner);
    DEREFERENCE_ENTITY(Entity, HANDLE_REF);

    return NO_ERROR;
}