#!/bin/sh
# $NUM is optional.
# $ACTION is optional.
. /etc/network.sh

LOCK_FILE=/tmp/.net.lock
local err;

do_if () {
    local action=$1
    local num=${2#wan}
    local action_now=$(nvram show wan_status_rule $num action)
    [ "$action_now" = "forcedown" -o "$action_now" = "forceup" ] && return
    to_log "do_if $1 $2"
    nvram replace attr wan_status_rule $num action "$action"
}

updown() {
    local num;
    local limit;

    case $1 in
        start)
            [ -z "$NUM" ] && {
                num=0
                limit=$(nvram get wan_num)
                while [ $num -lt $limit ]; do 
                    if [ "$(nvram show wan_main_rule $num enable)" = "1" ]; then
                        type=$(nvram show wan_lb_rule $num type)
                        [ "$type" = "alwayson" -o "$type" = "standby" ] && {
                            do_if forceup wan${num}
                        }
                    else
                        do_if forcedown wan${num}
                    fi
                    num=$(($num + 1))
                done
            } || {
                # check the wan specific is alive
                type=$(nvram show wan_lb_rule $NUM type)
                [ "$type" = "alwayson" -o "$type" = "standby" ] && {
                    do_if forceup wan${NUM}
                }
            }
        ;;
        stop)
            [ -z "$NUM" ] && {
                num=0
                limit=$(nvram get wan_num)
                while [ $num -lt $limit ]; do 
                    [ "$(nvram show wan_main_rule $num enable)" = "1" ] && {
                        do_if forcedown wan${num}
                    }
                    num=$(($num + 1))
                done
            } || {
                # check the wan specific is alive
                do_if forcedown wan${NUM}
            }
        ;;
    esac
}

upnp_start () {
    local num=$1
    local proto=$(nvram show wan_upnp_status_rule 0 proto)
    [ $proto = "wwan" -a "$(nvram show wan_wwan_probe_rule $num flag)" != "1" ] && {
        proto="directip"
        nvram replace attr wan_upnp_status_rule 0 proto directip
    }
    [ $proto != "wwan" -a "$(nvram show wan_wwan_probe_rule $num flag)" = "1" ] && {
        proto="wwan"
        nvram replace attr wan_upnp_status_rule 0 proto wwan
    }
    to_log "upnp proto is $proto"
    [ -z "$(nvram get wan${num}_upnp_proto)" ] && \
        nvram fset wan${num}_upnp_proto=$(nvram get wan${num}_proto)
    [ -z "$(nvram get wan${num}_upnp_ifname)" ] && \
        nvram fset wan${num}_upnp_ifname=$(nvram get wan${num}_ifname)
    # change wan upnp state to 2
    nvram replace attr wan_upnp_status_rule 0 state "2"
    # If wan proto now is the same with upnp proto
    # we do not change wan proto
    [ "$(nvram get wan${num}_proto)" = "$proto" ] && return
    case $proto in
        wwan)
            nvram set wan${num}_proto=wwan    
            nvram set wan${num}_ifname=ppp${num}
        ;;
        htc)
            nvram set wan${num}_proto=htc
            nvram set wan${num}_ifname=usb0
        ;;
        directip)
            nvram set wan${num}_proto=directip
            nvram set wan${num}_ifname=usb0
        ;;
        beceem)
            [ "$(nvram show appmgr_rule 0 beceem)" = "1" ] && { 
                nvram set wan${num}_proto=beceem
                nvram set wan${num}_ifname=eth0
            }
        ;;
        iphone)
            [ "$(nvram show appmgr_rule 0 iphone)" = "1" ] && { 
                nvram set wan${num}_proto=iphone
                nvram set wan${num}_ifname=eth0
            }
        ;;
        wimax)
            [ "$(nvram show appmgr_rule 0 wimax)" = "1" ] && { 
                nvram set wan${num}_proto=wimax
                nvram set wan${num}_ifname=wimax0
            }
        ;;
        barry)
            [ "$(nvram show appmgr_rule 0 barry)" = "1" ] && { 
                nvram set wan${num}_proto=barry
                nvram set wan${num}_ifname=ppp${num}
            }
        ;;
    esac
    # If product is P1, need to config ethernet port 
    # to wan or lan by wan proto
    [ "$(nvram show appmgr_rule 0 portcfg)" = "1" ] &&  \
        ezp-vlan esw config_p1_port lan
}

upnp_stop () {
    local num=$1
    local proto;
    local ifname;
    proto=$(nvram get wan${num}_upnp_proto)
    ifname=$(nvram get wan${num}_upnp_ifname)
    # change wan upnp state to 0
    nvram replace attr wan_upnp_status_rule 0 state "0"
    # If upnp proto is empty, it mean the upnp stop already executed.
    [ -z "$proto" -a -z "$ifname" ] && return
    [ -n "$proto" ] && {
        [ "$proto" = "$(nvram get wan${num}_proto)" ] || \
            nvram fset wan${num}_proto=$proto
        nvram unset wan${num}_upnp_proto
    }
    [ -n "$ifname" ] && {
        [ "$ifname" = "$(nvram get wan${num}_ifname)" ] || \
            nvram fset wan${num}_ifname=$ifname
        nvram unset wan${num}_upnp_ifname
    }
}

find_next_backup() {
    local backup=$(nvram show wan_lb_rule $1 backup)
    if [ "$backup" != "none" ]; then
        local backup_idx=${backup#wan}
        local action=$(nvram show wan_status_rule $backup_idx action)
        local type=$(nvram show wan_lb_rule $backup_idx type)
        [ "$action" = "up" ] && {
            case $type in
                backup_standby)
                    to_log "bakcup wan $backup standby"
                    do_if standby $backup
                ;;
                backup)
                    to_log "bakcup wan $backup down"
                    do_if down $backup
                ;;
            esac
        }
        find_next_backup $backup_idx
    fi
}

find_portidx() {
    widx=$1
    local i=0
    local vnum=$(nvram get vlan_rule_num)
    while [ "$i" -lt "$vnum" ]
    do
        local name=$(nvram show vlan_rule $i name)
        local idx=$(($widx + 1))
        [ "$name" = "WAN${idx}" ] && {
            vid=$(nvram show vlan_rule $i vid)
            j=0
            port_num=$(nvram get vlanport_rule_num)
            while [ "$j" -lt "$port_num" ]
            do
                [ "$vid" = "$(nvram show vlanport_rule $j pvid)" ] && {
                    port=$(nvram show vlanport_rule $j portid)
                    return $port
                }
                j=$(($j + 1))
            done
        }
        i=$(($i + 1))
    done
    return 255 
}

check_link() {
    local proto=$(nvram get wan${1}_proto)
    # if proto is not dhcp/static/pppoe, do not check 
    [ "$proto" = "dhcp" -o "$proto" = "static" -o \
      "$proto" = "pppoe" ] || return 1

    local sw_type=$(nvram get switch_type)
    local ret=0
    find_portidx $1
    local port=$?
    [ "$port" != "255" ] && {
        case $sw_type in
            esw)
                ret=$(switch portst link $port)
            ;;
            ar8316)
                port=$(($port + 1))
                ret=$(switch extportst link $port)
            ;;
        esac
    }
   
    return $ret
}

mode=$1
shift
lock $LOCK_FILE
err=0

case $mode in
    lb)
        local num=$(nvram get wan_num)
        local usb_wan=$(($num - 1))
        # change wan status
        to_log "####### wandetect loop #############"
        local cur=0
        while [ "$cur" -lt "$num" ]
        do 
            enable=$(nvram show wan_main_rule $cur enable)
            action=$(nvram show wan_status_rule $cur action)
            state=$(nvram show wan_status_rule $cur state)
            type=$(nvram show wan_lb_rule $cur type)
            to_log "[$cur] type:$type action:$action state:$state"
            check_link $cur
            local link=$?
            # execute based on $action
            # wandetect push state 2 to 3
            [ "$enable" = "1" ] && {
                [ "$state" -ge "2" ] &&  wandetect wan${cur} &
            }

            # ifup state from 0 to 2
            [ "$action" = "up" -o "$action" = "forceup" -o \
              "$action" = "standby" ] && {
                [ "$state" = "0" -a "$link" = "1" ] && {
                    # reset trycount to 0
                    nvram replace attr wan_status_rule ${cur} trycount 0
                    ifup wan${cur} &
                }
            }

            [ "$state" -lt "4" ] && {
                nvram replace attr vpn_status_rule $cur state 0
                nvram replace attr vpn_status_rule $cur action down
            }

            vpn_action=$(nvram show vpn_status_rule $cur action)
            vpn_state=$(nvram show vpn_status_rule $cur state)

            # ifup vpn state from 0 to 2
            [ "$vpn_action" = "up" -a "$vpn_state" = "0"  ] && ifup wan${cur} &

            # ifup state from 3 to 4 based on $action
            [ "$state" = "3" ] && [ "$action" = "up" -o "$action" = "forceup" ] && ifup wan${cur} &

            # ifup vpn state from 2 to 4 based on $action
            [ "$vpn_state" = "2" -a "$action" = "up" ] && {
                nvram replace attr vpn_status_rule $cur state 3
                ifup wan${cur} &
            }

            # down
            [ "$action" = "down" -o "$action" = "forcedown" ] && {
                [ "$state" -ge "1" ] && {
                    # For vpn client case, we don't want the carrier
                    # connection turned down, so we added a vpn_iface_on
                    # parameter
                    ifdown wan${cur} vpn_iface_on &
                }
            }
            # if $state is 4 and $action is standby, change $state to 3
            [ "$state" = "4" -a "$action" = "standby" ] && {
                ifdown wan${cur}
            }

            cur=$(($cur + 1)) 
        done

        # failover loop for wan num great than 1
        to_log "####### failover loop #############"
        cur=0
        while [ "$cur" -lt "$num" ]
        do
            enable=$(nvram show wan_main_rule $cur enable)
            type=$(nvram show wan_lb_rule $cur type)
            backup=$(nvram show wan_lb_rule $cur backup)
            state=$(nvram show wan_status_rule $cur state)
            action=$(nvram show wan_status_rule $cur action)
            proto=$(nvram get wan${cur}_proto)
            trycount="$(nvram show wan_status_rule $cur trycount)"
            maxcount="$(nvram show wan_main_rule $cur maxcount)"
            flag=0
            upnp_flag=1
            check_link $cur
            local link=$?
            
            to_log "[$cur] type:$type backup:$backup state:$state link:$link"
            to_log "[$cur] trycount:$trycount try max:$maxcount"
            [ "$enable" = "1" ] && {
                [ "$cur" = "$usb_wan" ] && {
                    upnp_enable=$(nvram show wanupnp_rule 0)
                    upnp_state=$(nvram show wan_upnp_status_rule 0 state)
                    upnp_proto=$(nvram show wan_upnp_status_rule 0 proto)
                    upnp_action=$(nvram show wan_upnp_status_rule 0 action)
                    wwan=$(nvram show appmgr_rule 0 wwan)
                    to_log "[$cur] upnp:$upnp_state upnp proto:$upnp_proto action:$upnp_action"
                    [ "$upnp_state" = "1" -a "$wwan" = "1" -a "$upnp_enable" = "1" ] && {
                        [ "$(nvram get prod_cat)" = "U" ] && {
                            if [ "$proto" = "htc" -o "$proto" = "iphone" \
                              "$proto" = "wimax" -o "$proto" = "barry" ]; then 
                                upnp_flag=0
                            else
                                upnp_flag=1
                            fi
                        }
                        [ "$upnp_flag" = "1" ] && {
                            if [ "$state" != "0" ]; then
                                do_if down wan$cur
                            else
                                upnp_action=$(nvram show wan_upnp_status_rule 0 action)
                                case $upnp_action in
                                    up)
                                        to_log "upnp start [$cur]"
                                        upnp_start $cur
                                    ;;
                                    down)
                                        to_log "upnp stop [$cur]"
                                        upnp_stop $cur
                                        usb-remove
                                        nvram replace attr wan_upnp_status_rule 0 action none
                                    ;;
                                esac
                            fi
                        }
                    }
                }

                # forceup
                [ "$action" = "forceup" -a "$state" = "4" ] && {
                # if action is forceup and state is 4, 
                # it mean gui change wan status and forceup is completed.
                # note: we cannot use do_if up $cur here
                    nvram replace attr wan_status_rule $cur action "up"
                }
               
                # if $state is 4 and VPN Client is enable 
                [ "$state" = "4" -a "$(nvram show wan_pptp_l2tp_rule $cur enable)" = "1" ] && {
                    nvram replace attr vpn_status_rule ${cur} action "up"
                }

                local BRAND="$(nvram get brand)"
                # action up
                [ "$type" = "alwayson" -a "$state" = "0" ] && {
                    [ "$cur" = "$usb_wan" ] && {
                        [ "$(nvram show wan_upnp_status_rule 0 state)" != "1" ] && do_if up wan$cur 
                    } || {
                        [ "$BRAND" = "APOLLO" -o "$BRAND" = "PROX" ] && {
                            [ "$(nvram get wan0_proto)" = "wisp" -a "$(nvram show wl0_apcli_rule 0 enable)" = "1" ] && {
                                to_log "restart wisp to scan channel"
                                /sbin/ezp-wl-ctrl apcli_swap_scan
                            }
                        }
                        do_if up wan$cur 
                    }
                }
                # standby
                [ "$type" = "backup_standby" -a "$state" = "0" ] && {
                    [ "$cur" = "$usb_wan" ] && {
                        [ "$(nvram show wan_upnp_status_rule 0 state)" != "1" ] && do_if up wan$cur 
                    } || {
                        do_if standby wan$cur 
                    }
                }

                # EZP: XXX [ "$link" = "0"  -a "$state" != "0" ] && {
                [ "$link" = "0" ] && {
                # if proto is dhcp/static/pppoe and link is down,
                # need to failover
                    trycount=9999
                }

                # backup 
                [ "$trycount" -ge "$maxcount" -a "$backup" != "none" ] && {
                # if trycount equal to try_max or try is timeout,up backup wan
                    do_if up $backup
                }

                # forcedown
                [ "$action" = "forcedown" -a "$state" = "0" ] && {
                # if action is forcedown and state is 0, 
                # it mean gui change wan status and ifdown is completed.
                    nvram replace attr wan_status_rule $cur action "down"
                }

                [ "$state" -ge "3" -a "$action" = "up" -a \
                  "$trycount" = "0" ] && {
                # if current wan state is great equal to 3,
                # and action is up, down backup wan
                    find_next_backup $cur
                }

                [ "$trycount" -ge "$maxcount" ] && {
                # if trycount equal to try_max,
                # down current wan
                    trycount=0
                # To avoid trycount add 1
                    flag=1
                    [ "$BRAND" = "PROX" -o "$BRAND" = "APOLLO" ] && {
                        [ "$cur" = "$usb_wan" ] && {
                            USB_TRYCOUNT="$(nvram show wan_status_rule $cur usb_trycount)"
                            USB_TRYCOUNT=$(($USB_TRYCOUNT + 1))
                            nvram replace attr wan_status_rule $cur usb_trycount $USB_TRYCOUNT
                        }
                    }
                    do_if down wan$cur
                }
               
                [ "$flag" != "1" ] && {
                    [ "$state" = "1" ] && trycount=$(($trycount + 1))
                    [ "$state" -ge "2" ] && {
                        trycount=0
                        [ "$BRAND" = "PROX" -o "$BRAND" = "APOLLO" ] && {
                            [ "$cur" = "$usb_wan" ] && nvram replace attr wan_status_rule $cur usb_trycount 0
                        } 
                    }
                }
                
                nvram replace attr wan_status_rule $cur trycount $trycount
            }
            cur=$(($cur + 1)) 
        done
    ;;
    wan_updown)
        updown $@
    ;;
esac
lock -u $LOCK_FILE
