/*********************************************************************/
/**               Copyright(c) 1995 Microsoft Corporation.	        **/
/*********************************************************************/

//***
//
// Filename:    rasapiif.c
//
// Description: Handles all the RASAPI32 calls
//
// History:     May 11,1996     NarenG      Created original version.
//
#include "ddm.h"
#include "util.h"
#include "objects.h"
#include "rasmanif.h"
#include "rasapiif.h"
#include "handlers.h"
#include "timer.h"
#include <time.h>
#include <mprapi.h>
#include <mprapip.h>

HPORT
RasGetHport( 
    IN HRASCONN hRasConnSubEntry 
);

DWORD
RasPortConnected( 
    IN HRASCONN         hRasConn,
    IN HRASCONN         hRasConnSubEntry,
    IN DEVICE_OBJECT *  pDevObj,
    IN HANDLE           hDIMInterface
)
{
    CONNECTION_OBJECT *         pConnObj;
    DWORD                       dwRetCode;
    ROUTER_INTERFACE_OBJECT *   pIfObject;

    //
    // Set this port to be notified by rasapi32 on disconnect.
    //

    dwRetCode = RasConnectionNotification( 
                                hRasConnSubEntry,
                                gblSupervisorEvents[NUM_DDM_EVENTS
                                   + (gblDeviceTable.NumDeviceBuckets*2)
                                   + DeviceObjHashPortToBucket(pDevObj->hPort)],
                                RASCN_Disconnection );

    if ( dwRetCode != NO_ERROR )
    {
        DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                   "RasConnectionNotification returned %d", dwRetCode );

        return( dwRetCode );
    }

    //
    // Get handle to the connection or bundle for this link
    //

    dwRetCode = RasPortGetBundle(NULL, pDevObj->hPort, &(pDevObj->hConnection));

    if ( dwRetCode != NO_ERROR )
    {
        DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                   "RasPortGetBundle returned %d", dwRetCode );

        return( dwRetCode );
    }

    do 
    {
        pIfObject = IfObjectGetPointer( hDIMInterface );

        if ( pIfObject == NULL )
        {
            RTASSERT( FALSE );
            dwRetCode = ERROR_NO_SUCH_INTERFACE;
            break;
        }
    
        //
        // If this interface was disconnected by DDMDisconnectInterface,
        // then do not let this device through.
        //

        if ( pIfObject->fFlags & IFFLAG_DISCONNECT_INITIATED )
        {
            dwRetCode = ERROR_PORT_DISCONNECTED;

            DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                       "RasPortConnected: Admin disconnected port" );
            break;
        }

        //
        // Allocate a connection object if it does not exist yet
        //

        pConnObj = ConnObjGetPointer( pDevObj->hConnection );

        if ( pConnObj == (CONNECTION_OBJECT *)NULL )
        {
            RASPPPIP    RasPppIp;
            RASPPPIPX   RasPppIpx;
            DWORD       dwSize;

            pConnObj = ConnObjAllocateAndInit(  hDIMInterface,
                                                pDevObj->hConnection );

            if ( pConnObj == (CONNECTION_OBJECT *)NULL )
            {
                dwRetCode = GetLastError();
                break;
            }   

            ConnObjInsertInTable( pConnObj );

            //
            // First get the projection info, make sure IP or IPX
            // were negotiated
            //

            dwSize              = sizeof( RasPppIpx );
            RasPppIpx.dwSize    = sizeof( RasPppIpx );

            dwRetCode = RasGetProjectionInfo( 
                                          hRasConn,
                                          RASP_PppIpx,
                                          &RasPppIpx,
                                          &dwSize );
            if ( dwRetCode != NO_ERROR )
            {
                pConnObj->PppProjectionResult.ipx.dwError = dwRetCode; 
            }
            else
            {
                pConnObj->PppProjectionResult.ipx.dwError = RasPppIpx.dwError; 

                ConvertStringToIpxAddress( 
                            RasPppIpx.szIpxAddress,
                            pConnObj->PppProjectionResult.ipx.bLocalAddress);

            }

            dwSize          = sizeof( RasPppIp );
            RasPppIp.dwSize = sizeof( RasPppIp );

            dwRetCode = RasGetProjectionInfo( 
                                            hRasConn,
                                            RASP_PppIp,
                                            &RasPppIp,
                                            &dwSize );
            if ( dwRetCode != NO_ERROR )
            {
                pConnObj->PppProjectionResult.ip.dwError =  dwRetCode;
            }
            else
            {
                pConnObj->PppProjectionResult.ip.dwError = RasPppIp.dwError; 

                ConvertStringToIpAddress( 
                            RasPppIp.szIpAddress,
                            &(pConnObj->PppProjectionResult.ip.dwLocalAddress));

                ConvertStringToIpAddress( 
                           RasPppIp.szServerIpAddress,
                           &(pConnObj->PppProjectionResult.ip.dwRemoteAddress));
            }

            if ((pConnObj->PppProjectionResult.ipx.dwError!=NO_ERROR )
                &&
                (pConnObj->PppProjectionResult.ip.dwError!=NO_ERROR ))
            {
                dwRetCode = ERROR_PPP_NO_PROTOCOLS_CONFIGURED;
                break;
            }

            pConnObj->fFlags    = CONN_OBJ_IS_PPP;
            pConnObj->hPort     = pDevObj->hPort;
        }
        else
        {
            //
            // Make sure that we are adding a link to a connection for the
            // same interface that initiated the connection.
            //
    
            if ( hDIMInterface != pConnObj->hDIMInterface )
            {
                dwRetCode = ERROR_INTERFACE_CONFIGURATION;

                break;
            }
        }

        pDevObj->hRasConn       = hRasConnSubEntry;
        GetSystemTimeAsFileTime( (FILETIME*)&(pDevObj->qwActiveTime) );

        //
        // Add this link to the connection block.
        //

        if ((dwRetCode = ConnObjAddLink(pConnObj, pDevObj)) != NO_ERROR)
        {
            break;
        }

        //
        // Notify router managers that we are connected if we have 
        // not done so already.
        //

        if ( !( pConnObj->fFlags & CONN_OBJ_PROJECTIONS_NOTIFIED ) )
        {
            RASDIALPARAMS   RasDialParams;
            BOOL            fPassword;

            dwRetCode = IfObjectConnected( 
                                        hDIMInterface, 
                                        (HCONN)pDevObj->hConnection,
                                        &(pConnObj->PppProjectionResult) );

            if ( dwRetCode != NO_ERROR )
            {
                break;
            }

            pConnObj->fFlags |= CONN_OBJ_PROJECTIONS_NOTIFIED;

            //
            // Get username and domain name
            //

            ZeroMemory( &RasDialParams, sizeof( RasDialParams ) );
            RasDialParams.dwSize = sizeof( RasDialParams );
            wcscpy( RasDialParams.szEntryName, pIfObject->lpwsInterfaceName );

            dwRetCode = RasGetEntryDialParams(  gblpRouterPhoneBook, 
                                                &RasDialParams, 
                                                &fPassword);

            if ( dwRetCode == NO_ERROR )
            {
                wcscpy( pConnObj->wchUserName, RasDialParams.szUserName );
                wcscpy( pConnObj->wchDomainName, RasDialParams.szDomain );  
                ZeroMemory( &RasDialParams, sizeof( RasDialParams ) );
            }
            else
            {
                dwRetCode = NO_ERROR;
            }

            wcscpy( pConnObj->wchInterfaceName,  pIfObject->lpwsInterfaceName );

            GetSystemTimeAsFileTime( (FILETIME*)&(pDevObj->qwActiveTime) ); 
            pConnObj->qwActiveTime  = pDevObj->qwActiveTime; 
            pConnObj->InterfaceType = pIfObject->IfType;

            pIfObject->dwLastError = NO_ERROR;

            //
            // If this was initiated by an admin api. Let the caller
            // know that we are connected.
            //

            if (pIfObject->hEventNotifyCaller != INVALID_HANDLE_VALUE)
            {
                SetEvent( pIfObject->hEventNotifyCaller );

                CloseHandle( pIfObject->hEventNotifyCaller );

                pIfObject->hEventNotifyCaller = INVALID_HANDLE_VALUE;
            }
        }

        //
        // Reduce the media count for this device
        //

        if ( !(pDevObj->fFlags & DEV_OBJ_MARKED_AS_INUSE) )
        {
            if ( pDevObj->fFlags & DEV_OBJ_ALLOW_ROUTERS )
            {
                MediaObjRemoveFromTable( pDevObj->wchDeviceType );
            }

            pDevObj->fFlags |= DEV_OBJ_MARKED_AS_INUSE;

            gblDeviceTable.NumDevicesInUse++;

            //
            // Possibly need to notify the router managers of
            // unreachability
            //

            IfObjectNotifyAllOfReachabilityChange( FALSE, 
                                                   INTERFACE_OUT_OF_RESOURCES );
        }

        RasSetRouterUsage( pDevObj->hPort, TRUE );

    }while( FALSE );

    if ( dwRetCode != NO_ERROR )
    {
        DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                   "RasPortConnected: Cleaning up hPort=%d, error %d",
                    pDevObj->hPort, dwRetCode );

        RasApiCleanUpPort( pDevObj );

        return( dwRetCode );
    }

    return( NO_ERROR );
}

//**
//
// Call:        RasConnectCallback
//
// Returns:     None
//
// Description: Callback function that will be called by RASAPI32 for any
//              state change.
//
BOOL
RasConnectCallback(
    IN DWORD        dwCallbackId,
    IN DWORD        dwSubEntryId,
    IN HRASCONN     hRasConn,  
    IN DWORD        dwMsg, 
    IN RASCONNSTATE RasConnState,
    IN DWORD        dwError, 
    IN DWORD        dwExtendedError
)
{
    DWORD                       dwIndex;
    ROUTER_INTERFACE_OBJECT *   pIfObject       = NULL;
    DEVICE_OBJECT *             pDevObj         = NULL;
    HANDLE                      hDIMInterface   = (HANDLE)UlongToPtr(dwCallbackId);
    HRASCONN                    hRasConnSubEntry;
    DWORD                       dwRetCode;
    HPORT                       hPort;
    LPWSTR                      lpwsAudit[2];

    if ( dwMsg != WM_RASDIALEVENT )
    {
        RTASSERT( dwMsg == WM_RASDIALEVENT );
        return( TRUE );
    }

    switch( RasConnState )
    {

    case RASCS_Connected:
    case RASCS_SubEntryConnected:
    case RASCS_SubEntryDisconnected:
    case RASCS_Disconnected: 
    case RASCS_PortOpened:
        break;

    default:

        if ( dwError != NO_ERROR )
        {
            break;
        }
        else
        {
            //
            // Ignore these intermediate events
            //

            return( TRUE );
        }
    }

    EnterCriticalSection( &(gblDeviceTable.CriticalSection) );

    EnterCriticalSection( &(gblpInterfaceTable->CriticalSection) );

    do
    {
        //  
        // Get pointer to device object and hRasConn of the device
        //

        dwRetCode = RasGetSubEntryHandle(   hRasConn,
                                            dwSubEntryId,
                                            &hRasConnSubEntry );

        if ( dwRetCode != NO_ERROR )
        {
            DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                        "RasGetSubEntryHandle( 0x%x, 0x%x, 0x%x ) = %d",
                        hRasConn, dwSubEntryId, &hRasConnSubEntry, dwRetCode );

            if ( dwError == NO_ERROR )
            {
                dwError = dwRetCode;
            }
        }
        else
        {
            hPort = RasGetHport( hRasConnSubEntry );

            if ( hPort == (HPORT)INVALID_HANDLE_VALUE )
            {
                RTASSERT( FALSE );

                dwRetCode = ERROR_INVALID_PORT_HANDLE;

                if ( dwError == NO_ERROR )
                {
                    dwError = dwRetCode;
                }
            }
            else
            {
                if ( ( pDevObj = DeviceObjGetPointer( hPort ) ) == NULL )
                {
                    dwRetCode = ERROR_NOT_ROUTER_PORT;
                }
                else
                {
                    if ( !( pDevObj->fFlags & DEV_OBJ_ALLOW_ROUTERS ) )
                    {
                        dwRetCode = ERROR_NOT_ROUTER_PORT;
                    }
                    else
                    {
                        dwRetCode = NO_ERROR;
                    }
                }

                if ( dwError == NO_ERROR )
                {
                    dwError = dwRetCode;
                }
            }
        }

        if ( dwError == NO_ERROR )
        {
            switch( RasConnState )
            {
            case RASCS_PortOpened:

                pDevObj->fFlags         |= DEV_OBJ_OPENED_FOR_DIALOUT;
                pDevObj->hRasConn       = hRasConnSubEntry;
                break;

            case RASCS_Connected:
            case RASCS_SubEntryConnected:

                DDM_PRINT(gblDDMConfigInfo.dwTraceId, TRACE_FSM,
	                "RasConnectCallback:PortConnected,dwSubEntryId=%d,hPort=%d",
                    dwSubEntryId, hPort );

                dwError = RasPortConnected( hRasConn,
                                            hRasConnSubEntry,
                                            pDevObj,
                                            hDIMInterface );
                break;

            case RASCS_SubEntryDisconnected:
            case RASCS_Disconnected: 

                pDevObj->fFlags     &= ~DEV_OBJ_OPENED_FOR_DIALOUT;
                pDevObj->hRasConn   = (HRASCONN)NULL;

                break;

            default:

                RTASSERT( FALSE );
                break;
            }

            if ( ( RasConnState == RASCS_Connected )        ||
                 ( RasConnState == RASCS_SubEntryConnected )||
                 ( RasConnState == RASCS_PortOpened ) )
            {
                if ( dwError == NO_ERROR )
                {
                    break;
                }
            }
        }
        else
        {
            if ( pDevObj != NULL )
            {
                pDevObj->fFlags     &= ~DEV_OBJ_OPENED_FOR_DIALOUT;
                pDevObj->hRasConn   = (HRASCONN)NULL;
            }
        }

        DDM_PRINT(gblDDMConfigInfo.dwTraceId, TRACE_FSM,
	           "RasConnectCallback:Could not connect to SubEntry %d,dwError=%d",
               dwSubEntryId, dwError );

        //
        // Has the bundle failed to connect?
        //

        pIfObject = IfObjectGetPointer( hDIMInterface );

        if ( pIfObject == NULL )
        {
            RTASSERT( FALSE );
            dwError = ERROR_NO_SUCH_INTERFACE;
            break;
        }

        --pIfObject->dwNumSubEntriesCounter;

        if ( ( pIfObject->dwNumSubEntriesCounter == 0 ) ||
             ( RasConnState == RASCS_Disconnected ) ||
             !(pIfObject->fFlags & IFFLAG_DIALMODE_DIALALL))
        {
            if ( pIfObject->State == RISTATE_CONNECTED )
            {
                //
                // Interface is already connected so it doesn't matter if this
                // device failed.
                //

                break;
            }

            DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                       "RasConnectCallback:Could not connect to interface %ws",
                       pIfObject->lpwsInterfaceName );

            DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                    "RasConnectCallback: hanging up 0x%x", pIfObject->hRasConn);
            RasHangUp( pIfObject->hRasConn );

            pIfObject->hRasConn = (HRASCONN)NULL;

            //
            // If the admin as initiated a disconnect or we are out of 
            // retries
            //

            if ( ( pIfObject->fFlags & IFFLAG_DISCONNECT_INITIATED ) ||
                 ( pIfObject->dwNumOfReConnectAttemptsCounter == 0 ) )
            {
                //
                // Mark as unreachable due to connection failure the admin did
                // not disconnect.
                //

                if ( !( pIfObject->fFlags & IFFLAG_DISCONNECT_INITIATED ) )
                {
                    pIfObject->fFlags |= IFFLAG_CONNECTION_FAILURE;
                }

                IfObjectDisconnected( pIfObject );

                IfObjectNotifyOfReachabilityChange(     
                                                pIfObject,
                                                FALSE,
                                                INTERFACE_CONNECTION_FAILURE );

                //
                // If we were disconnected by the admin then we should
                // immediately go to the reachable state.
                //

                if ( pIfObject->fFlags & IFFLAG_DISCONNECT_INITIATED )
                {
                    IfObjectNotifyOfReachabilityChange(     
                                                pIfObject,
                                                TRUE,
                                                INTERFACE_CONNECTION_FAILURE );
                }

                pIfObject->dwLastError = dwError;

                if ( pDevObj != NULL )
                {
		            lpwsAudit[0] = pIfObject->lpwsInterfaceName;
		            lpwsAudit[1] = pDevObj->wchPortName;

		            DDMLogErrorString( ROUTERLOG_CONNECTION_ATTEMPT_FAILED, 
                                       2, lpwsAudit, dwError, 2 );
                }

                //
                // If this was initiated by an admin api. Let the caller
                // know that we are not connected.
                //

                if (pIfObject->hEventNotifyCaller != INVALID_HANDLE_VALUE)
                {
                    SetEvent( pIfObject->hEventNotifyCaller );

                    CloseHandle( pIfObject->hEventNotifyCaller );

                    pIfObject->hEventNotifyCaller = INVALID_HANDLE_VALUE;
                }
            }
            else
            {
                //
                // Otherwise we try again
                //

                pIfObject->dwNumOfReConnectAttemptsCounter--;

                //
                // Stagger the reconnectime randomly between 0 and twice the
                // configured reconnect time.   
                //

                srand( (unsigned)time( NULL ) );
            
                TimerQInsert( 
                    pIfObject->hDIMInterface,
                    rand()%((pIfObject->dwSecondsBetweenReConnectAttempts*2)+1),
                    ReConnectInterface );

            }
        }
    }
    while( FALSE );

    LeaveCriticalSection( &(gblpInterfaceTable->CriticalSection) );

    LeaveCriticalSection( &(gblDeviceTable.CriticalSection) );

    return( TRUE );
}

//**
//
// Call:        RasConnectionInitiate
//
// Returns:     NO_ERROR         - Success
//              Non-zero returns - Failure
//
// Description: Called to initiate a demand-dial connection
//
DWORD
RasConnectionInitiate( 
    IN ROUTER_INTERFACE_OBJECT *    pIfObject,
    IN BOOL                         fRedialAttempt
) 
{
    RASDIALEXTENSIONS   RasDialExtensions;
    RASDIALPARAMS       RasDialParams;
    DWORD               dwXportIndex;
    DWORD               dwRetCode;
    RASENTRY            re;
    DWORD               dwSize;
    RASEAPUSERIDENTITY* pRasEapUserIdentity = NULL;

    //
    // Do not try to connect if the interface is disabled or out of resources
    // or the service is paused or the interface is marked as unreachable due
    // to connection failure.
    //

    if ( !( pIfObject->fFlags & IFFLAG_ENABLED ) )
    {
        return( ERROR_INTERFACE_DISABLED );
    }

    if ( pIfObject->fFlags & IFFLAG_OUT_OF_RESOURCES )
    {
        return( ERROR_INTERFACE_HAS_NO_DEVICES );
    }

    if ( gblDDMConfigInfo.pServiceStatus->dwCurrentState == SERVICE_PAUSED )
    {
        return( ERROR_SERVICE_IS_PAUSED );
    }

    //
    // If this is not a redial attempt then we reset the reconnect attempts
    // counter and unset the admin disconnected flag if it was set.
    //

    if ( !fRedialAttempt )
    {
        pIfObject->dwNumOfReConnectAttemptsCounter = 
                                        pIfObject->dwNumOfReConnectAttempts;

        pIfObject->fFlags &= ~IFFLAG_DISCONNECT_INITIATED;
    } 
    else
    {
        //
        // Do not allow the reconnect attempt to go thru if the admin has 
        // disconnected this interface.
        //

        if ( pIfObject->fFlags & IFFLAG_DISCONNECT_INITIATED )
        {
            return( ERROR_INTERFACE_DISCONNECTED );
        }
    }

    //
    // Build PppInterfaceInfo structure to pass down to RasDial that will pass
    // it on to PPP.
    //

    for ( dwXportIndex = 0;
          dwXportIndex < gblDDMConfigInfo.dwNumRouterManagers;
          dwXportIndex++ )
    {
        switch( gblRouterManagers[dwXportIndex].DdmRouterIf.dwProtocolId )
        {
        case PID_IPX:


            if (pIfObject->Transport[dwXportIndex].fState & RITRANSPORT_ENABLED)
            {
                pIfObject->PppInterfaceInfo.hIPXInterface =
                                pIfObject->Transport[dwXportIndex].hInterface;
            }
            else
            {
                pIfObject->PppInterfaceInfo.hIPXInterface=INVALID_HANDLE_VALUE;
            }

            break;

        case PID_IP:

            if (pIfObject->Transport[dwXportIndex].fState & RITRANSPORT_ENABLED)
            {
                pIfObject->PppInterfaceInfo.hIPInterface =
                                pIfObject->Transport[dwXportIndex].hInterface;
            }
            else
            {
                pIfObject->PppInterfaceInfo.hIPInterface = INVALID_HANDLE_VALUE;
            }

            break;

        default:

            RTASSERT( FALSE );
            break;
        }
    }

    pIfObject->PppInterfaceInfo.IfType  = pIfObject->IfType;
    pIfObject->dwNumSubEntriesCounter   = pIfObject->dwNumSubEntries;
    
    //
    // Initiate the connection
    //

    ZeroMemory( &RasDialExtensions, sizeof( RasDialExtensions ) );
    RasDialExtensions.dwSize     = sizeof( RasDialExtensions );
    RasDialExtensions.dwfOptions = RDEOPT_Router;
    RasDialExtensions.reserved   = (ULONG_PTR)&(pIfObject->PppInterfaceInfo);

    ZeroMemory( &RasDialParams, sizeof( RasDialParams ) );

    RasDialParams.dwSize        = sizeof( RasDialParams );
    RasDialParams.dwCallbackId  = PtrToUlong(pIfObject->hDIMInterface);
    RasDialParams.dwSubEntry    = 0;

    wcscpy( RasDialParams.szCallbackNumber, TEXT("*") );
    wcscpy( RasDialParams.szEntryName,      pIfObject->lpwsInterfaceName );

    //
    // Do we need to call RasEapGetIdentity?
    //

    dwRetCode = RasGetEapUserIdentity(
                            gblpRouterPhoneBook,
                            pIfObject->lpwsInterfaceName,
                            RASEAPF_NonInteractive,
                            NULL,
                            &pRasEapUserIdentity);

    if ( ERROR_INVALID_FUNCTION_FOR_ENTRY == dwRetCode )
    {
        //
        // This entry does not require RasEapGetIdentity. Get its credentials.
        //

        dwRetCode = MprAdminInterfaceGetCredentialsInternal(  
                                        NULL,
                                        pIfObject->lpwsInterfaceName,
                                        (LPWSTR)&(RasDialParams.szUserName), 
                                        (LPWSTR)&(RasDialParams.szPassword), 
                                        (LPWSTR)&(RasDialParams.szDomain) );

        if ( dwRetCode != NO_ERROR )
        {
            return( ERROR_NO_INTERFACE_CREDENTIALS_SET );
        }
    }
    else if ( NO_ERROR != dwRetCode )
    {
        if ( ERROR_INTERACTIVE_MODE == dwRetCode )
        {
            dwRetCode = ERROR_NO_INTERFACE_CREDENTIALS_SET;
        }

        return( dwRetCode );
    }
    else
    {
        wcscpy( RasDialParams.szUserName, pRasEapUserIdentity->szUserName );

        RasDialExtensions.RasEapInfo.dwSizeofEapInfo =
                                pRasEapUserIdentity->dwSizeofEapInfo;
        RasDialExtensions.RasEapInfo.pbEapInfo =
                                pRasEapUserIdentity->pbEapInfo;
    }

    if(     (0 != gblDDMConfigInfo.cDigitalIPAddresses)
        ||  (0 != gblDDMConfigInfo.cAnalogIPAddresses))
    {        

        ZeroMemory(&re, sizeof(RASENTRY));

        re.dwSize = sizeof(RASENTRY);

        dwSize = sizeof(RASENTRY);

        if(ERROR_SUCCESS == (dwRetCode = RasGetEntryProperties(
                                            gblpRouterPhoneBook,
                                            pIfObject->lpwsInterfaceName,
                                            &re,
                                            &dwSize,
                                            NULL,
                                            NULL)))
        {   
            if(RASET_Vpn == re.dwType)
            {
                char *pszMungedPhoneNumber = NULL;
                char szPhoneNumber[RAS_MaxPhoneNumber + 1];
                WCHAR wszMungedPhoneNumber[RAS_MaxPhoneNumber + 1];

                //
                // Convert the phonenumber to ansi
                //

                WideCharToMultiByte(
                                CP_ACP,
                                0,
                                re.szLocalPhoneNumber,
                                -1,
                                szPhoneNumber,
                                sizeof( szPhoneNumber ),
                                NULL,
                                NULL );

                //
                // Munge the phonenumber
                //

                dwRetCode = MungePhoneNumber(
                                    szPhoneNumber,
                                    gblDDMConfigInfo.dwIndex,
                                    &dwSize,
                                    &pszMungedPhoneNumber);

                if(ERROR_SUCCESS == dwRetCode)
                {
                    //
                    // Change the munged phonenumber to widechar
                    //

                    MultiByteToWideChar( CP_ACP,
                                         0,
                                         pszMungedPhoneNumber,
                                         -1,
                                         wszMungedPhoneNumber,
                                         RAS_MaxPhoneNumber + 1);

                    if ( wcslen( wszMungedPhoneNumber ) <= RAS_MaxPhoneNumber)
                    {
                        wcscpy( RasDialParams.szPhoneNumber, 
                                wszMungedPhoneNumber );

                        DDM_PRINT(gblDDMConfigInfo.dwTraceId, TRACE_FSM,
                                  "Munged Phone Number=%ws",
                                  RasDialParams.szPhoneNumber);

                        //
                        // Increase the index so that we try the
                        // next FEP the next time this is dialed.
                        //

                        gblDDMConfigInfo.dwIndex += 1;

                        LocalFree( pszMungedPhoneNumber );
                    }            
                }
            }
        }
    }

    dwRetCode = RasDial( &RasDialExtensions,
                         gblpRouterPhoneBook,
                         &RasDialParams, 
                         2,
                         RasConnectCallback,
                         &(pIfObject->hRasConn) );

    //
    // Zero out these since they contained sensitive password information
    //

    ZeroMemory( &RasDialParams, sizeof( RasDialParams ) );

    RasFreeEapUserIdentity( pRasEapUserIdentity );

    if ( dwRetCode != NO_ERROR )
    {
        return( dwRetCode );
    }

    pIfObject->State = RISTATE_CONNECTING;

    pIfObject->fFlags |= IFFLAG_LOCALLY_INITIATED;

    return( NO_ERROR );
}