/*
 *============================================================================
 * Copyright (c) 1994-95, Microsoft Corp.
 *
 * File:    map.c
 *
 * Routes can be added to and deleted from the IP routing table by other
 * means. Therefore, it is necessary for any protocol using these functions
 * to reload the routing tables periodically.
 *============================================================================
 */

#include "pchrip.h"
#pragma hdrstop

//----------------------------------------------------------------------------
// GetIpAddressTable
//
// This function retrieves the list of addresses for the logical interfaces
// configured on this system.
//----------------------------------------------------------------------------

DWORD
GetIPAddressTable(
    OUT PMIB_IPADDRROW *lplpAddrTable,
    OUT LPDWORD lpdwAddrCount
)
{

    DWORD                   dwSize = 0, dwErr = 0;
    PMIB_IPADDRTABLE        pmiatTable = NULL;
    

    

    *lplpAddrTable = NULL;
    *lpdwAddrCount = 0;
    

    do
    {

        //
        // retrieve ip address table.  First call to find size of
        // structure to be allocated.
        //
        
        dwErr = GetIpAddrTable( pmiatTable, &dwSize, TRUE );

        if ( dwErr != ERROR_INSUFFICIENT_BUFFER )
        {
            dbgprintf( "GetIpAddrTable failed with error %x\n", dwErr );

            RipLogError( RIPLOG_ADDR_INIT_FAILED, 0, NULL, dwErr );

            break;
        }


        //
        // allocate requiste buffer
        //
        
        pmiatTable = HeapAlloc( GetProcessHeap(), 0 , dwSize );

        if ( pmiatTable == NULL )
        {
            dwErr = ERROR_NOT_ENOUGH_MEMORY;
            
            dbgprintf( "GetIpAddrTable failed with error %x\n", dwErr );

            RipLogError( RIPLOG_ADDR_ALLOC_FAILED, 0, NULL, dwErr );

            break;
        }


        //
        // now retrieve address table
        //

        dwErr = GetIpAddrTable( pmiatTable, &dwSize, TRUE );
                    
        if ( dwErr != NO_ERROR )
        {
            dbgprintf( "GetIpAddrTable failed with error %x\n", dwErr );

            RipLogError( RIPLOG_ADDR_INIT_FAILED, 0, NULL, dwErr );

            break;
        }

        *lpdwAddrCount = pmiatTable-> dwNumEntries;

        *lplpAddrTable = pmiatTable-> table;

        return NO_ERROR;
        
    } while ( FALSE );


    //
    // Error condition
    //

    if ( pmiatTable ) 
    {
        HeapFree( GetProcessHeap(), 0, pmiatTable );
    }

    return dwErr;
}


//----------------------------------------------------------------------------
// FreeIPAddressTable
//
// This function releases the memory allocated for the IP address table by
// the GetIpAddressTable API.
//----------------------------------------------------------------------------

DWORD
FreeIPAddressTable(
    IN PMIB_IPADDRROW lpAddrTable
    )
{

    PMIB_IPADDRTABLE pmiatTable = NULL;


    pmiatTable = CONTAINING_RECORD( lpAddrTable, MIB_IPADDRTABLE, table );

    if ( pmiatTable != NULL )
    {
        HeapFree( GetProcessHeap(), 0, pmiatTable );

        return NO_ERROR;    
    }

    return ERROR_INVALID_PARAMETER;
}


//----------------------------------------------------------------------------
// GetRouteTable
//
// This function retrieves the route table.
//----------------------------------------------------------------------------

DWORD
GetRouteTable(
    OUT LPIPROUTE_ENTRY *lplpRouteTable,
    OUT LPDWORD lpdwRouteCount
    )
{

    DWORD                   dwErr = (DWORD) -1, dwSize = 0;
    PMIB_IPFORWARDTABLE     pmiftTable = NULL;

    

    *lplpRouteTable = NULL;
    *lpdwRouteCount = 0;


    do
    {

        //
        // get size of buffer required.
        //
        
        dwErr = GetIpForwardTable( pmiftTable, &dwSize, TRUE );

        if ( dwErr != ERROR_INSUFFICIENT_BUFFER )
        {
            dbgprintf( "GetIpNetTable failed with error %x\n", dwErr );

            RipLogError( RIPLOG_ROUTEINIT_FAILED, 0, NULL, dwErr );

            break;
        }


        //
        // allocate requiste buffer space
        //

        pmiftTable = HeapAlloc( GetProcessHeap(), 0, dwSize );

        if ( pmiftTable == NULL )
        {
            dwErr = ERROR_NOT_ENOUGH_MEMORY;
            
            dbgprintf( "GetIpAddrTable failed with error %x\n", dwErr );

            RipLogError( RIPLOG_RTAB_INIT_FAILED, 0, NULL, dwErr );

            break;
        }


        //
        // now retrieve route table
        //

        dwErr = GetIpForwardTable( pmiftTable, &dwSize, TRUE );
                    
        if ( dwErr != NO_ERROR )
        {
            dbgprintf( "GetIpNetTable failed with error %x\n", dwErr );

            RipLogError( RIPLOG_RTAB_INIT_FAILED, 0, NULL, dwErr );

            break;
        }

        *lpdwRouteCount = pmiftTable-> dwNumEntries;

        *lplpRouteTable = (LPIPROUTE_ENTRY) pmiftTable-> table;

        return NO_ERROR;
        
    } while ( FALSE );


    //
    // Error condition
    //

    if ( pmiftTable ) 
    {
        HeapFree( GetProcessHeap(), 0, pmiftTable );
    }

    return dwErr;
}


//----------------------------------------------------------------------------
// FreeIPRouteTable
//
// This function releases the memory allocated for the IP route table by
// the GetIpAddressTable API.
//----------------------------------------------------------------------------

DWORD
FreeRouteTable(
    IN LPIPROUTE_ENTRY lpRouteTable
    )
{

    PMIB_IPFORWARDTABLE pmiftTable = NULL;


    pmiftTable = CONTAINING_RECORD( lpRouteTable, MIB_IPFORWARDTABLE, table );

    if ( pmiftTable != NULL )
    {
        HeapFree( GetProcessHeap(), 0, pmiftTable );

        return NO_ERROR;    
    }

    return ERROR_INVALID_PARAMETER;
}


//----------------------------------------------------------------------------
// AddRoute
//
// This function adds a route to the IP stack
//----------------------------------------------------------------------------

DWORD
AddRoute(
    IN DWORD dwProtocol,
    IN DWORD dwType,
    IN DWORD dwIndex,
    IN DWORD dwDestVal,
    IN DWORD dwMaskVal,
    IN DWORD dwGateVal,
    IN DWORD dwMetric
    )
{

    DWORD                   dwErr = 0;

    MIB_IPFORWARDROW        mifr;

    
    ZeroMemory( &mifr, sizeof( MIB_IPFORWARDROW ) );

    mifr.dwForwardDest      = dwDestVal;
    mifr.dwForwardMask      = dwMaskVal;
    mifr.dwForwardPolicy    = 0;
    mifr.dwForwardNextHop   = dwGateVal;
    mifr.dwForwardIfIndex   = dwIndex;
    mifr.dwForwardType      = dwType;
    mifr.dwForwardProto     = MIB_IPPROTO_NT_AUTOSTATIC;
    mifr.dwForwardMetric1   = dwMetric;


    dwErr = CreateIpForwardEntry( &mifr );

    if ( dwErr == ERROR_ALREADY_EXISTS )
    {
        //
        // Bug # : 405469
        //
        //  For the case where IPRIP (Rip Listener) is running at the
        //  same time as the RemoteAccess service.
        //  In this case the IPHLPAPI go via the IPRTRMGR to the stack
        //  and trying to create a route that already exists will fail
        //  with ERROR_ALREADY_EXISTS.  To work around this case, set
        //  the forward entry.
        //
        
        dwErr = SetIpForwardEntry( &mifr );
    }
    
    if ( dwErr != NO_ERROR )
    {
        dbgprintf( "Create/Set IpForwardEntry failed with error %x\n", dwErr );

        RipLogError( RIPLOG_ADD_ROUTE_FAILED, 0, NULL, dwErr );
    }

    return dwErr;
}



//----------------------------------------------------------------------------
// DelRoute
//
// This function deletes a route to the IP stack
//----------------------------------------------------------------------------

DWORD
DeleteRoute(
    IN DWORD dwIndex,
    IN DWORD dwDestVal,
    IN DWORD dwMaskVal,
    IN DWORD dwGateVal
    )
{

    DWORD                   dwErr = 0;

    MIB_IPFORWARDROW        mifr;

    
    ZeroMemory( &mifr, sizeof( MIB_IPFORWARDROW ) );


    mifr.dwForwardDest      = dwDestVal;
    mifr.dwForwardMask      = dwMaskVal;
    mifr.dwForwardPolicy    = 0;
    mifr.dwForwardProto     = MIB_IPPROTO_NT_AUTOSTATIC;
    mifr.dwForwardNextHop   = dwGateVal;
    mifr.dwForwardIfIndex   = dwIndex;


    dwErr = DeleteIpForwardEntry( &mifr );

    if ( dwErr != NO_ERROR )
    {
        dbgprintf( "DeleteIpForwardEntry failed with error %x\n", dwErr );

        RipLogError( RIPLOG_DELETE_ROUTE_FAILED, 0, NULL, dwErr );
    }

    return dwErr;
}


//----------------------------------------------------------------------------
// DelRoute
//
// This function deletes a route to the IP stack
//----------------------------------------------------------------------------

DWORD
ReloadIPAddressTable(
    OUT PMIB_IPADDRROW *lplpAddrTable,
    OUT LPDWORD lpdwAddrCount
    )
{
    return GetIPAddressTable( lplpAddrTable, lpdwAddrCount );
}