#!/bin/sh

if [ -z "$1" ]; then
    echo "you need specified arguements"
    exit
fi        

. /usr/bin/scriptlib
. /usr/bin/l2tpc-header
. /usr/bin/l2tpc-customer

TUN_IDX=$1
L2TP_RESULT_FILE="/var/run/l2tpc-result-$TUN_IDX"
PIDFILE_PPPD="/var/run/ppp-l2tpc.pid"
RESET_FILE="/var/run/l2tpc-reset-$TUN_IDX"
PAP_FILE="/etc/ppp/pap-secrets"
CHAP_FILE="/etc/ppp/chap-secrets"
DONT_UPDATE_WANTYPE="/var/run/dont_update_wantype"
L2TP_RELOAD_FLAG="/var/run/l2tpc-reconf"
L2TP_LNSPORT=1701
PORTSCAN="/usr/bin/port-scan"
PORTSCAN_RESULT="/var/run/pscan-result"   
PPP_PID=
PPP_IF= 

test_lns_exist()
{
    logger -t "l2tpc" "Try to ping L2TP Server ! Wait for reply ..." 
    echo "Try to ping L2TP Server ! Wait for reply ..." 
    
    # Try 3 Times
    for i in 1 2 3
    do
        got=0
        CFG=`ping -c1 $L2TP_LNSSERVER`
        if [ $? = 0 ] ; then
            stt=0
            for s in $CFG
            do
                if [ $stt = 1 ] ; then
                    L2TP_LNSSERVER=${s%:*}
                    got=1
                    break		 
                fi
            
                if [ $s = "from" ] ; then
                    stt=1
                fi	   
            done
        fi
        
        [ $got = 1 ] && break
        sleep 1
    done

    if [ $got = 0 ] ; then	
        echo "Ping packet can't reach the L2TP Server !" 
        logger -t "l2tpc" "Ping packet can't reach the L2TP Server !" 
        logger -t "l2tpc" "May the packet drop by the server's firewall or your router behind the firewall !?"          
        exit 1 
    fi
}

test_lns_port()
{
    local timeout=5
    local idx=0
    
    logger -t "l2tpc" "Send detect packet to L2TP Server ! Wait for reply ..." 
    echo "Send detect packet to L2TP Server ! Wait for reply ..." 
    $PORTSCAN -u $L2TP_LNSSERVER $L2TP_LNSPORT $L2TP_LNSPORT &
    local pscan_pid=$!

    while [ true ]; do
        if [ -f "$PORTSCAN_RESULT" ]; then
            rm -f $PORTSCAN_RESULT 
            return
        fi

        sleep 1
        idx=$((idx+1))
        [ $idx -gt $timeout ] && break
    done    
    
    kill $pscan_pid > /dev/null 2>&1
    reset_connect

    logger -t "l2tpc" "Request packet can't reach the port of the L2TP Server used ($L2TP_LNSPORT) !" 
    logger -t "l2tpc" "May the packet drop by the server's firewall or your router behind the firewall !?"
    echo "Request packet can't reach the port of the Server used !"
    exit 1
} 

# Write L2TP connection infomation (pid, interface name, ip ...) to CSID
log_l2tp_info() 
{      
    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_PID $TUN_IDX`
    wrcsman "$addr $PPP_PID"

    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_IFNAME $TUN_IDX`
    wrcsman "$addr \"$PPP_IF"

    #echo `ifconfig $PPP_IF  | grep P-t-P | cut -d ':' -f2 | cut -d ' ' -f1`
    PPP_VIRTUAL_IP=`ifconfig $PPP_IF  | grep P-t-P | cut -d ':' -f2 | cut -d ' ' -f1`
    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_VIRTUAL_IP $TUN_IDX`
    wrcsman "$addr {$PPP_VIRTUAL_IP}"

    #echo `ifconfig $PPP_IF  | grep P-t-P | cut -d ':' -f3 | cut -d ' ' -f1`
    PPP_REMOTE_IP=`ifconfig $PPP_IF  | grep P-t-P | cut -d ':' -f3 | cut -d ' ' -f1`
    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_REMOTE_IP $TUN_IDX`
    wrcsman "$addr {$PPP_REMOTE_IP}"
    return 1
}                                   

# Setup Route if need 
setup_route()
{
    addr=`get_csid_addr $CSID_C_L2TP_CLI_ROUTE $TUN_IDX`
    ROUTEING="`rdcsman $addr str`"
     if [ "$ROUTEING" == "" ]; then
        return 
    fi 

    route_fail=0
    default_gw=""
    if [ "$ROUTEING" == "0.0.0.0/0" ]; then
        route_fail=1

        addr=`get_csid_addr $CSID_C_3G_AUTOBAK_ENABLE 0`
        enable_3g_autobak=`rdcsman $addr u8`
        if [ $enable_3g_autobak -eq 1 ]; then 
            addr=`get_csid_addr $CSID_S_FLASHOFDM_IF_GW 0`
            ofdm_gw="`rdcsman $addr ipv4`" 
            if [ "$ofdm_gw" != "0.0.0.0" ]; then
                route_fail=0
                default_gw="$ofm_gw"
            fi

            addr=`get_csid_addr $CSID_S_3G_IF_GW 0`
            _3g_gw="`rdcsman $addr ipv4`" 
            if [ "$_3g_gw" != "0.0.0.0" ]; then
                route_fail=0
                default_gw="$_3g_gw"
            fi
        fi

        # IF Not in failover 
        if [ "$default_gw" == "" ]; then
            addr=`get_csid_addr $CSID_S_LOCAL_WAN_GW 0`
            default_gw="`rdcsman $addr ipv4`"  
            if [ "$default_gw" != "0.0.0.0" ]; then
                route_fail=0
            fi
        fi

        echo "route add -host $L2TP_LNSSERVER gw $default_gw"
        route add -host $L2TP_LNSSERVER gw $default_gw 
        echo "route delete -host $L2TP_LNSSERVER gw $default_gw >/dev/null 2>&1" >> $RESET_FILE
    fi  

    if [ $route_fail -eq 0 ]; then 
        echo "route add -net $ROUTEING dev $PPP_IF"
        route add -net $ROUTEING dev $PPP_IF  
        echo "route delete -net $ROUTEING dev $PPP_IF >/dev/null 2>&1" >> $RESET_FILE
    else
        echo "ROUTING ERROR: can't route to L2TP Server"
    fi
}

# Setup NAT if need
setup_nat()
{
    addr=`get_csid_addr $CSID_C_L2TP_CLI_NAT $TUN_IDX`
    is_nat=`rdcsman $addr u8`
    if [ $is_nat -eq 1 ]; then
        get_lan_range lan_ip lan_mask
        echo "iptables -t nat -A POSTROUTING -s $lan_ip/$lan_mask -o $PPP_IF -j MASQUERADE"
        iptables -t nat -A POSTROUTING -s $lan_ip/$lan_mask -o $PPP_IF -j MASQUERADE
        echo "iptables -t nat -D POSTROUTING -s $lan_ip/$lan_mask -o $PPP_IF -j MASQUERADE >/dev/null 2>&1" >> $RESET_FILE
    fi 
}

# Generate L2TP Client's secret file in /etc/ppp/...
gen_secret_file()
{
    addr=`get_csid_addr $CSID_C_L2TP_CLI_USER $TUN_IDX`
    account="`rdcsman $addr str`" 

    addr=`get_csid_addr $CSID_C_L2TP_CLI_PASSWORD $TUN_IDX`
    passwd="`rdcsman $addr str`"    
    echo "$account * $passwd *" > $PAP_FILE.l2tpc-$TUN_IDX
    echo "$account * $passwd *" > $CHAP_FILE.l2tpc-$TUN_IDX
 
    # Make sure L2TP Client's account/password wouldn't conflict with other PPP Services
    [ -f $PAP_FILE  ] && mv $PAP_FILE $PAP_FILE.orig
    [ -f $CHAP_FILE ] && mv $CHAP_FILE $CHAP_FILE.orig
    mv $PAP_FILE.l2tpc-$TUN_IDX $PAP_FILE
    mv $CHAP_FILE.l2tpc-$TUN_IDX $CHAP_FILE 
}

# Restore from L2TP Client's secret to original secret file
restore_secret_file()
{
    [ -f $PAP_FILE.orig  ] && mv $PAP_FILE.orig $PAP_FILE
    [ -f $CHAP_FILE.orig ] && mv $CHAP_FILE.orig $CHAP_FILE    
}

reset_connect()
{
    rm -f $L2TP_RESULT_FILE		
    rm -f $DONT_UPDATE_WANTYPE
    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_PID $TUN_IDX`
    wrcsman "$addr 0"
    restore_secret_file
}

check_network_status()
{
    addr=`get_csid_addr $CSID_S_LOCAL_WAN_STATUS 0`
    wan_status=`rdcsman $addr u8`
    if [ "$wan_status" == "$LOCAL_WAN_STATUS_CONNECT" ]; then
        return;
    fi
    echo "Main WAN isn't connected !!"

    addr=`get_csid_addr $CSID_C_3G_AUTOBAK_ENABLE 0`
    autobak_enable=`rdcsman $addr u8`    

    addr=`get_csid_addr $CSID_S_3G_AUTOBAK_STATUS 0`
    autobak_status=`rdcsman $addr u8` 
    if [ "$autobak_enable" == "1" ] && 
       [ "$autobak_status" == "$AUTOBAK_STATUS_3G_CONNECT" ]; then
        return;
    fi
    echo "3G Autobak isn't connected !!"

    addr=`get_csid_addr $CSID_C_FAILOVER_LOADSHARING_ENABLE 0`
    loadsharing_enable=`rdcsman $addr u8` 
    if [ "$loadsharing_enable" == "1" ]; then
        addr=`get_csid_addr $CSID_S_LOADSHARING_STATUS 0`
        loadsharing_status=`rdcsman $addr u8` 
        if [ "$loadsharing_status" == "$LOADSHARING_STATUS_CONNECT" ]; then
            return;
        fi
        echo "LoadSharing isn't connected !"
    else
        addr=`get_csid_addr $CSID_S_FAILOVER_STATUS 0`
        failover_status=`rdcsman $addr u8` 
        if [ "$failover_status" == "$FAILOVER_STATUS_CONNECT" ]; then
            return;
        fi         
        echo "Failover isn't connected !"
    fi  

    # Reset PID
    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_PID $TUN_IDX`
    wrcsman "$addr 0"

    logger -t "l2tpc" "L2TP Client #$TUN_IDX waited for WAN connecting... !"
    echo "L2TP Client #$TUN_IDX don't action since WAN isn't connected !"
    exit 1
}         

chg_txqlen()
{              
    # wan_type:    
    #  16 -> LOCAL_WANTYPE_3G        0x10
    #  17 -> LOCAL_WANTYPE_IBURST    0x11
    #  21 -> LOCAL_WANTYPE_FLASHOFDM 0x15
    #  22 -> LOCAL_WANTYPE_S3G       0x16
    #  64 -> LOCAL_WANTYPE_PPPOE     0x40
    #  144 -> LOCAL_WANTYPE_DIALUP   0x90
    addr=`get_csid_addr $CSID_C_LOCAL_WANTYPE 0`
    wan_type="`rdcsman $addr u32`"    
    if [ $wan_type -eq 16 ] || [ $wan_type -eq 17 ] ||
       [ $wan_type -eq 21 ] || [ $wan_type -eq 22 ] ||
       [ $wan_type -eq 64 ] || [ $wan_type -eq 144 ]; then
        addr=`get_csid_addr $CSID_S_LOCAL_WAN_IF_NAME 0`
        wan_if="`rdcsman $addr str`"
        tmp="`expr substr $wan_if 1 3`"

        if [ "$tmp" == "ppp" ]; then 
            echo "set ifconfig $wan_if txqueuelen to 3"
            ifconfig $wan_if txqueuelen 3 > /dev/null 2>&1
        else
            echo "Trick: set ifconfig ppp0 txqueuelen to 3"
            ifconfig ppp0 txqueuelen 3 > /dev/null 2>&1
        fi
    fi
}  

get_host_ip()
{    
    local time=0
    local timeout=5
    local domain_name=`rdcsman $1 str`
    if [ "$domain_name" == "" ]; then
       echo "No IP/Domain of L2TP Client ID $TUN_IDX !" 
       logger -t "l2tpc" "No Peer IP/Domain of L2TP Client ID $TUN_IDX "
       reset_connect
       exit 1
    fi

    L2TP_LNSSERVER=`getHostIP $domain_name &`
    local gethip_pid=$!
    while [ true ]; do
        if [ -n "$L2TP_LNSSERVER" ]; then
            addr=`get_csid_addr $CSID_C_L2TP_CLI_PEERIP $TUN_IDX`    
            wrcsman "$addr {$L2TP_LNSSERVER}"
            break
        fi

        sleep 1
        time=$(($time+1))
        [ $time -gt $timeout ] && break 
    done

	if [ -z "$L2TP_LNSSERVER" ] ; then
        echo "Cannot resolved IP, Please Check Host's Domain Name"                                        
        logger -t "l2tpc" "Please Check Peer IP/Domain of L2TP Client ID $TUN_IDX Again!"
		kill $gethip_pid > /dev/null 2>&1
        reset_connect
		exit 1
	fi
}
 

waitfor_ppp_negotiaction()
{
    local idx=0
    while [ true ]; do     
        # Check the L2TP connection 
        if [ ! -f $PIDFILE_PPPD ] ; then
            echo "Can't find $PIDFILE_PPPD. May PPP negotiation failed !! Check PPP option, plz !"
            logger -t "l2tpc" "Can't find $PIDFILE_PPPD. May PPP negotiation failed !! Check PPP option, plz !"
            reset_connect
            exit 1  
        fi 

        if [ ! -f $DONT_UPDATE_WANTYPE ]; then
            echo "PPP negotiation complete !!"
            break
        fi 

        if [ -f $L2TP_RESULT_FILE ] && [ -z "`cat $L2TP_RESULT_FILE | grep OK`" ]; then
            echo "Connecting failed !! May PPP negotiation failed !! Check PPP option, plz !"
            logger -t "l2tpc" "Connecting failed !!. May PPP negotiation failed !! Check PPP option, plz !"
            reset_connect
            exit 1  
        fi

        if [ $idx -ge 30 ]; then
            echo "L2TP Connecting ... timeout !!"
            logger -t "l2tpc" "L2TP Connecting ... timeout !!"
            break
        fi

        idx=$((idx+1))
        sleep 1
        echo "L2TP Connecting ... $idx sec"
    done

    sl_get_ppp_PID_IFname $PIDFILE_PPPD PPP_PID PPP_IF
    if [ $? != 0 ] ; then		
        echo "Can't find PPPD/L2TP process"
        reset_connect
        exit 1
    fi

    # Show the cnt status
    logger -t "l2tpc" "Link is up and running on interface $PPP_IF (PID: $PPP_PID)"
    echo "L2TP's status : Link is up and running on interface $PPP_IF"
    echo "IF=$PPP_IF  PID=$PPP_PID" 
}

reload_l2tpd()
{
    # Make l2tpd reload the /etc/l2tp/l2tp.conf
    touch $L2TP_RELOAD_FLAG 

    # kill pre-l2tpd when error
    if [ -r "$L2TP_RESULT_FILE" ]; then 
        result=`cat $L2TP_RESULT_FILE | cut -d ' ' -f1`
        if [ ! -z $result ] && [ $result == "ERR" ]; then    
            killall l2tpd
        fi        
    fi

    if [ -z "`ps | grep l2tpd | grep -v xl2tpd |grep -v grep`" ]; then
        l2tpd -d 65535
    fi
}

main()
{
    # Test if the tunnel had created
    addr=`get_csid_addr $CSID_S_L2TP_CLI_PEER_PID $TUN_IDX`
    cnt_pid=`rdcsman $addr u16`
    if [ $cnt_pid -gt 0 ] && [ $cnt_pid -lt 65535 ]; then
        echo "Tunnel $TUN_IDX is already running (PID:$cnt_pid)"
        exit 1
    else
        wrcsman "$addr -1"
    fi
 
    check_network_status;

    # Change Tx Quele length for 3G (no longer need)
    # chg_txqlen    

    # Get the address of L2TP_LNSSERVER
    #addr=`get_csid_addr $CSID_C_L2TP_CLI_PEERIP $TUN_IDX`
    #L2TP_LNSSERVER="`rdcsman $addr ipv4`" # old version
    addr=`get_csid_addr $CSID_C_L2TP_CLI_PEERIP_STR $TUN_IDX`    
    get_host_ip $addr
    echo "L2TP_LNSSERVER=$L2TP_LNSSERVER"  
    if [ -z "$L2TP_LNSSERVER" ]; then
        reset_connect

        echo "Unknown L2TP Server address !!"
        logger -t "l2tpc" "Unknown L2TP Server address !!"
        exit 1
    fi

    # Check the connection between Server and Client
    addr=`get_csid_addr $CSID_C_L2TP_CLI_DETECT_LNS 0`
    detect_type=`rdcsman $addr u8`   
    if [ $detect_type -eq $L2TP_DETECT_SERVER_BY_PORTSCAN ]; then 
        if [ -f "$PORTSCAN" ]; then
            test_lns_port
        else    
            echo "can't find $PORTSCAN utility !! Start the connection directly ..."
            logger -t "l2tpc" "can't find $PORTSCAN utility !! Start the connection directly ..."
        fi
    elif [ $detect_type -eq $L2TP_DETECT_SERVER_BY_PING ]; then        
        test_lns_exist # old version 
    else
        echo "Don't detect LNS in advance. Start the connection directly !"
    fi
    
    # Clear last ppp auth fail temp file
    rm -rf /var/run/ppp_auth* $L2TP_RESULT_FILE   
    if [ -f $RESET_FILE ]; then
        (. $RESET_FILE)
        rm -f $RESET_FILE
    fi
    
    # Write config to /etc/...
    gen_secret_file    
    gen_l2tpd_conf  # uvm /usr/uo/l2tp.conf.uo > /etc/l2tp/l2tp.conf

    # init or reload l2tpd with the update config
    reload_l2tpd

    # Start Connect & Log L2TP Session ID to /var/run/
    echo "L2TP start to connect! ( l2tp-control start-session $L2TP_LNSSERVER )"
    logger -t "l2tpc" "L2TP start to connect to \"$L2TP_LNSSERVER\" "
    touch $DONT_UPDATE_WANTYPE
    l2tp-control "start-session $L2TP_LNSSERVER" > $L2TP_RESULT_FILE    
    sleep 3
    
    # Waiting Time for negotiaction
    waitfor_ppp_negotiaction
    
    # Restore original PPP secrets                          
    restore_secret_file

    # Some configuration after the L2TP connection established
    log_l2tp_info 
    setup_route
    setup_nat

    # Set larger MTU to avoid fragment packets 
    ifconfig $PPP_IF mtu 1500
}

#
#  Main ()
# 
main

