#!/bin/sh

dsa_driver=$(grep -s DEVTYPE=dsa /sys/class/net/*/uevent)

[ -z "dsa_driver" ] && exit -1

#For example WR5000:
#ethernetPortOrder="lan0 lan1 lan2 lan3 eth1"
#ethernetPortNum="0 1 2 3 47"
ethernetPortOrder=$(uci -q get system.board.ethernetPortOrder)
ethernetPortNum=$(uci -q get system.board.ethernetPortNum)
wan_phy=$(uci -q get system.board.wan_phy)
cpu_lan_port=5
PHY_BASEADDR=32

ifname2portnum() {
    local target_name="$1"
    local idx=0
    local found_num=""

    for ifname in $ethernetPortOrder; do
        if [ "$ifname" = "$target_name" ]; then
            found_num=$(echo $ethernetPortNum | awk -v idx=$((idx+1)) '{print $idx}')
            echo "$found_num"
            return
        fi
        idx=$((idx + 1))
    done

    echo "-1"
}

detect_switch() {
    if command -v switch an8855 >/dev/null || switch an8855 port get matrix 0 >/dev/null 2>&1; then
    	cpu_lan_port=5
        echo "an8855"
    else
        echo "unknown"
    fi
}

switch_reset() {
    local sw=$(detect_switch)
    case "$sw" in
        an8855) an8855_reset 
		;;
    esac
}

an8855_set_matrix() {
    local port=$1
    local mask=$2
    hex=$(printf "0x%x" $mask) 
    switch an8855 port set matrix "$port" "$hex"
}

an8855_reset() {
	#reset all port matrix
	local base_default=0x3F
	local mask
 	for portnum in $ethernetPortNum; do
 		mask=$((base_default & ~(1 << portnum)))
 		switch_set_matrix "$portnum" "$mask"
 	done
}

switch_set_matrix() {
    local port=$1
    local mask=$2
    local sw=$(detect_switch)
    case "$sw" in
        an8855) 
			[ -n "$wan_phy" -a "$port" == $(($wan_phy+$PHY_BASEADDR)) ] || {
				an8855_set_matrix "$port" "$mask" 
			}
		;;
    esac
}

isolate_all() {
	local portnum=""
    for lan in $ethernetPortOrder; do
        portnum=$(ifname2portnum "$lan")
        switch_set_matrix "$portnum" $((1 << cpu_lan_port))
    done

    exit 0
}

an8855_isolate_ports() {
    local iso_lans="$@"
    local portnum
    local base_default

    [ -z "$iso_lans" ] && {
    	echo "Error, No parameters!"
    	exit 1
    }

    for port in $iso_lans; do
        portnum=$(ifname2portnum "$port")
        if [ "$portnum" = "-1" ]; then
            echo "Error, ifname error"
            exit 1
        fi
    done

    switch_reset

    #iso_lans only access CPU port
    for lan in $iso_lans; do
        portnum=$(ifname2portnum "$lan")
        switch_set_matrix "$portnum" $((1 << cpu_lan_port))
    done

    #other lan port can accss each other
    for lan in $ethernetPortOrder; do
        portnum=$(ifname2portnum "$lan")
        local iso=0
        for i in $iso_lans; do
            [ "$lan" = "$i" ] && { iso=1; break; }
        done
        [ $iso = 1 ] && continue

        base_default=0x3F
        base_default=$((base_default & ~(1 << portnum)))
        for il in $iso_lans; do
            ihw=$(ifname2portnum "$il")
            base_default=$((base_default & ~(1 << ihw)))
        done

        switch_set_matrix "$portnum" "$base_default"
    done
}

isolate_ports()
{
	local sw=$(detect_switch)
    case "$sw" in
		an8855) 
			an8855_isolate_ports $@
        ;;
	esac

	exit 0
}

get_wan()
{
	echo "xxxxxxxxxxx get wan 47" > /dev/console
	echo "47"
}

action=$1
shift

case "$action" in
    reset)
        switch_reset
        ;;
    all)
        isolate_all
        ;;
    isolate)
        isolate_ports "$@"
        ;;
    get)
        [ "$1" = "wan" ] && get_wan
        ;;
    *)
        echo "Usage:"
        echo "  $0 isolate <lan0 lan1 ...>"
        echo "  $0 all -- Isolate all lan ports"
        echo "  $0 reset -- All lan ports can access with each other"
        echo "  $0 get wan"
        ;;
esac
