#!/bin/bash
#
# VERSION=22
# CHANGES="fix an issue from the crontab task"

### contstants ###
export PATH=$PATH:/sbin/:/bin:/usr/sbin:/usr/bin

### functions ###
function log () {
	echo "[init_network] ${1}"
}

function cdr2mask() {
    # Number of args to shift, 255..255, first non-255 byte, zeroes
    set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
    [ $1 -gt 1 ] && shift $1 || shift
    echo ${1-0}.${2-0}.${3-0}.${4-0}
}

function add_routes() {

	routing=$(/usr/fallback/beroconf get root routing | grep -v failed)

	IFS=,
	for i in $routing ; do
		net=$(echo $i | cut -d "/" -f1)
		netmask_bits=$(echo $i | cut -d "/" -f2)
		netmask=$(cdr2mask $netmask_bits)
		gateway=$(echo $i | cut -d "/" -f3)
		log "Adding: route add -net $net netmask $netmask gw $gateway"
		/sbin/route add -net $net netmask $netmask gw $gateway
	done
}

function setup_cron {
        if [ ! -d ${CRONDIR} ] ; then
                mkdir -p /usr/conf/cron
        fi

        crontab -l | grep -v "update_dns" > /tmp/crontab.network
        if [ "${1}" = "on" ]; then
                log "Adding cron-job."
                echo "*/5 * * * * /usr/fallback/update-interfaces update_dns" >> /tmp/crontab.network
        else
                log "Removing cron-job."
        fi
        crontab /tmp/crontab.network
        rm -f /tmp/crontab.network
}

function setup_switch_vlan () {
	/sbin/mdio f 0:1600 > /dev/null
	/sbin/mdio w 0:0:6:5:128 > /dev/null
	/sbin/mdio w 0:0:14:16:4 > /dev/null
	/sbin/mdio w 0:0:7:0:2 > /dev/null
	/sbin/mdio w 0:0:7:16:2 > /dev/null
	/sbin/mdio w 0:0:7:4:10 > /dev/null
	/sbin/mdio w 0:0:7:20:11 > /dev/null
	/sbin/mdio w 0:0:15:14:20 > /dev/null
	/sbin/mdio w 0:0:15:15:2 > /dev/null
	/sbin/mdio w 0:0:15:20:100 > /dev/null
	/sbin/mdio w 0:0:15:18:13 > /dev/null
	/sbin/mdio w 0:0:15:14:4 > /dev/null
	/sbin/mdio w 0:0:15:15:2 > /dev/null
	case "$(/usr/fallback/beroconf get root lan-mode | grep -v failed)" in
		lan-wan|bonding)
			;;
		*)
			# disable port 2
			/sbin/mdio w 0:0:7:18:1	>/dev/null
			;;
	esac
	/sbin/mdio w 0:0:6:1:67 > /dev/null
}

function setup_switch () {
	/sbin/mdio f 0:1600 > /dev/null
	/sbin/mdio w 0:0:7:18:1 > /dev/null
	/sbin/mdio w 0:0:6:1:67 > /dev/null
}

function setup_second_mac () {
	#calculate new mac address
        current_mac=$(cat /sys/class/net/eth0/address)
        new_mac="$(echo $current_mac | cut -d ':' -f 1,2,3):06:$(echo $current_mac | cut -d':' -f 5,6)"
       
        #setup new mac address on WAN Vlan 
        ifconfig eth0.11 down
        ifconfig eth0.11 hw ether $new_mac
        ifconfig eth0.11 up
        
        #setup new mac address on MSP
        /sbin/mdio m $new_mac
}

function conf_lan_wan () {
	# setup switch
	IS_LAN_DHCP=$(/usr/fallback/beroconf get root lan-dhcp | grep -v failed)
	if [[ ! -z ${IS_LAN_DHCP} ]] && [[ ${IS_LAN_DHCP} -eq 1 ]]; then
		setup_switch_vlan
	fi

	# get eth0 up for vlan to work
	/sbin/ifconfig eth0 0.0.0.0 up

	# configure gateway-side
	/sbin/insmod /lib/modules/8021q.ko
	
	/sbin/ifup eth0.10
	vconfig add eth0 11
	
	# netconfig server on lan needs this:
	route add 255.255.255.255 eth0.10

	# enable routing
	echo 1 > /proc/sys/net/ipv4/ip_forward
	
	# enable masquerading
	iptables -A POSTROUTING -t nat -o eth0.11 -j MASQUERADE
	
	# setup second mac
	setup_second_mac
	
	# configure switch-side
	if [[ -z ${IS_LAN_DHCP} ]] || [[ ! ${IS_LAN_DHCP} -eq 1 ]]; then
		setup_switch_vlan
	fi
	/sbin/ifup eth0.11

	# ping broadcast
	if [ -z "$(/usr/bin/sqlite /usr/conf/ari.db .dump | /bin/grep 'ping_broadcast=0')" ]; then
		/bin/ping -c 3 255.255.255.255 >/dev/null
	fi
}

function deconf_lan_wan () {
	# disable routing
	echo 0 > /proc/sys/net/ipv4/ip_forward
	iptables -D POSTROUTING -t nat -o eth0.11 -j MASQUERADE

	# deconfigure interfaces
	/sbin/ifdown eth0.10
	/sbin/ifdown eth0.11
	/sbin/rmmod /lib/modules/8021q.ko

	/sbin/ifconfig eth0 down
}


function conf_lan_bonding () {

	# configure switch-side
	setup_switch

	# configure interface
	/sbin/ifup eth0
}

function deconf_lan_bonding () {
	# deconfigure bonding interface
	/sbin/ifdown eth0
}

function conf_lan_single () {

	# okay, we start with the default settings depending on how many lan-ports we have
	case "$(/usr/fallback/beroconf get root lan-ports | grep -v failed)" in
		1)
			iface="eth0"
			/sbin/ifconfig eth0 10.0.0.2 netmask 255.0.0.0 up
			/sbin/route add default eth0
			;;
		2)
			iface="eth0.10"
			setup_switch_vlan
			/sbin/ifconfig eth0 0.0.0.0 up
			/sbin/insmod /lib/modules/8021q.ko
			;;
	esac

	# bring up interface
	/sbin/ifup ${iface}
}

function deconf_lan_single () {
	lan_ports=$(/usr/fallback/beroconf get root lan-ports | grep -v failed)
	iface="eth0"
	if [ "${lan_ports}" = "2" ]; then
		iface="${iface}.10"
	fi

	/sbin/ifdown ${iface}
	if [ "${lan_ports}" = "2" ]; then
		/sbin/rmmod /lib/modules/8021q.ko
	fi
}

function conf_lan_single_vlan () {
	# get eth0 up for vlan to work
	/sbin/ifconfig eth0 0.0.0.0 up

	# get the vlan-ids
	vlan_id=$(/usr/fallback/beroconf get root vlan-id | grep -v failed)

	# configure interface
	/sbin/insmod /lib/modules/8021q.ko
	/sbin/ifup eth0.${vlan_id}
}

function deconf_lan_single_vlan () {
	# get the vlan-ids
	vlan_id=$(/usr/fallback/beroconf get root vlan-id | grep -v failed)

	# deconfigure interface
	/sbin/ifdown eth0.${vlan_id}
	/sbin/rmmod /lib/modules/8021q.ko

	/sbin/ifconfig eth0 down
}

function eval_lan_ports () {

	# old gateways always have one port
	gateway_hw=$(cat /sys/class/beronet/gateway/type)
	if [ ${gateway_hw} -lt 30 ]; then
		/usr/fallback/beroconf set root lan-ports 1
		log "Detected Network-Ports: 1"
		return
	fi

	# get current lan-port-count to check if something has changed
	lan_ports=$(/usr/fallback/beroconf get root lan-ports | grep -v failed)
	if [ -z "${lan_ports}" ]; then
		lan_ports=1
	fi

	/sbin/ifup eth1
	sleep 2
	/sbin/mdio f 0:1600 > /dev/null
	phy_id_lb_1=$(expr match "$(/sbin/mdio r 0:0:0:2)" ".*register_value=\([0-9]*\)")

	if [ -z "${phy_id_lb_1}" ]; then
		/usr/fallback/beroconf set root lan-ports 1
		log "Detected Network-Ports: 1"
		return
	fi

	# we always reset lan-mode if count of ports has changed
	if [ ${phy_id_lb_1} -ne 65535 ]; then
		if [ ${lan_ports} -eq 2 ]; then
			/usr/fallback/beroconf set root lan-mode single
		fi
		/usr/fallback/beroconf set root lan-ports 1
		log "Detected Network-Ports: 1"
		return
	fi

	if [ ${lan_ports} -eq 1 ]; then
		/usr/fallback/beroconf set root lan-mode single
	fi
	/usr/fallback/beroconf set root lan-ports 2
	log "Detected Network-Ports: 2"
}

function start_network () {
	# if lan-mode is not set, we need to initialize it
	eval_lan_ports

	# update /etc/network/interfaces
	/usr/fallback/update-interfaces

	# make sure eth1 has the address configured
	/sbin/ifdown eth1; /sbin/ifup eth1

	# evaluate lan-mode and configure accordingly
	lan_mode=$(/usr/fallback/beroconf get root lan-mode | grep -v failed)
	if [ -z "${lan_mode}" ]; then
		lan_mode=single
	fi
	log "Configuring network for mode: ${lan_mode}"
	case "${lan_mode}" in
		lan-wan)
			conf_lan_wan
			;;
		bonding)
			conf_lan_bonding
			;;
		single)
			vlan=$(/usr/fallback/beroconf get root vlan-enable | grep -v failed)
			if [ "${vlan}" = "1" ]; then
				conf_lan_single_vlan
			else
				conf_lan_single
			fi
			;;
	esac

	add_routes
	#interfaces should be up now, check now if dns servers are functioning and write resolv.conf again
	/usr/fallback/update-interfaces update_dns
	#add a cron task to check the DNS
	setup_cron "on"
}

function stop_network () {
	# evaluate lan-mode and deconfigure accordingly
	lan_mode=$(/usr/fallback/beroconf get root lan-mode | grep -v failed)
	log "Deconfiguring network for mode: ${lan_mode}"
	case "${lan_mode}" in
		lan-wan)
			deconf_lan_wan
			;;
		bonding)
			deconf_lan_bonding
			;;
		*)
			vlan=$(/usr/fallback/beroconf get root vlan-enable | grep -v failed)
			if [ "${vlan}" = "1" ]; then
				deconf_lan_single_vlan
			else
				deconf_lan_single
			fi
			;;
	esac
	#remove cron task
	setup_cron "off"
}

### remove prep_phy ###
if [ ! "$(/usr/fallback/beroconf get root prep_phy | grep -v failed)" = "removed" ]; then
	if [[ -f /usr/fallback/fw_printenv ]] && [[ -f /usr/fallback/fw_setenv ]]; then
		IS_REMOVED=0
		/bin/mount -o remount,rw /
		/bin/mknod /dev/mtd1 c 90 2 &>/dev/null
		if [ ! "$(/usr/fallback/fw_printenv | /bin/grep prep_phy | /bin/grep -v watchdog)" = "" ]; then
			/usr/fallback/fw_setenv boot_ins  ### remove it for reproducing scenario (since boot_ins is defined by prep_phy)
			/usr/fallback/fw_setenv prep_phy
			/usr/fallback/fw_setenv watchdog mw.l 0x11400000 30000000
		fi
		if [ "$(/usr/fallback/fw_printenv | /bin/grep prep_phy | /bin/grep -v watchdog)" = "" ]; then
			IS_REMOVED=1
		fi
		/bin/rm -f /dev/mtd1
		/bin/mount -o remount,ro /
		if [ "${IS_REMOVED}" = "1" ]; then
			/usr/fallback/beroconf set root prep_phy removed
		fi
	fi
fi

### main ###
case "${1}" in
	start)
		if ! /sbin/udhcpc -v; then
			mount -o remount,rw /
			ln -sf /bin/busybox /sbin/udhcpc
			mount -o remount,ro /
		fi
		start_network
		;;
	stop)
		stop_network
		;;
	restart|reload)
		stop_network
		start_network
		;;
	*)
		echo "Usage: ${0} {start|stop|restart|reload}" >&2
		exit 1
esac
