#!/bin/sh
#
# Copyright 2003 Meru Networks
# All rights reserved.
#

TUNNEL_MODULE_NAME="ip_gre"
IPTUNNEL="/sbin/ip tunnel"

VLAN_MODULE_NAME="8021q"
VCONFIG="/usr/sbin/vconfig"
VLANLOG="/opt/meru/var/log/vlan.log"
VLANPROCDIR=/proc/net/vlan
IP_RULE_PREF=200
RT_BASE=10
VLAN_RANGE=512

if [ -f /etc/init.d/meru-functions ]; then
	. /etc/init.d/meru-functions
else
	echo "/etc/init.d/meru-functions must exist to use $0"; exit 1
fi

set_params

start() 
{
    echo "========= vlan start: `date` ============" > $VLANLOG

    #insert a module 8021q.0
    modprobe ${VLAN_MODULE_NAME} 2>&1 >> $VLANLOG || fail "${VLAN_MODULE_NAME} is not available"
    modprobe ${TUNNEL_MODULE_NAME} 2>&1 >> $VLANLOG || fail "${TUNNEL_MODULE_NAME} is not available"

    #change VLAN interface naming convention to meru.VLAN_ID like meru.5
    ${VCONFIG} set_name_type  VLAN_PLUS_VID_NO_PAD >> /dev/null
    
    insmod /opt/meru/kernel/ipt_vlan_routing.mod 2>&1 >> $VLANLOG
    iptables -t mangle -A OUTPUT -j vlan_routing 2>&1 >> $VLANLOG
}

stop() 
{
    # first remove all VLAN interfaces if any        
    for i in `cat ${VLANPROCDIR}/config | egrep -v "VLAN|Name-Type"| awk '{print $1}'`
    do
	/sbin/ifconfig $i down
	${VCONFIG} rem $i
    done

    # And remove all tunnels
    for i in `$IPTUNNEL show | egrep -v "^gre0" | egrep "gre/ip" | egrep -o "^[^:]+"`
    do
	/sbin/ifconfig $i down
	${IPTUNNEL} del $i

        iptables -t mangle -D PREROUTING -i $i -j MARK --set-mark $[$vlan_index+$RT_BASE]
    done

    modprobe -r ${TUNNEL_MODULE_NAME}
    modprobe -r ${VLAN_MODULE_NAME}

    #kernel is smart enough to remove all routing entries pointing to deleted intefaces
    #only handle policy rule
    #there is no way of getting WLAN index so brutally interate 1 to VLAN_RANGE 
    vlan_index=2
    
    while [ $vlan_index -lt $[$VLAN_RANGE+1] ]
    do  
	/sbin/ip rule del fwmark $[$vlan_index+$RT_BASE] table $[$vlan_index+$RT_BASE] pref ${IP_RULE_PREF} > /dev/null 2>&1
	/sbin/ip rule del fwmark $[$vlan_index+$VLAN_RANGE+$RT_BASE] table $[$vlan_index+$VLAN_RANGE+$RT_BASE] pref ${IP_RULE_PREF} > /dev/null 2>&1  		

	vlan_index=`expr $vlan_index + 1`
    done

    iptables -t mangle -D OUTPUT -j vlan_routing
    
    rmmod ipt_vlan_routing
}

# VLAN index
# VLAN ID
# IP address
# netmask
# gateway
# interface (1 or 2)
# type (gre or vlan)
create() 
{

    VLAN_INDEX=$2
    VLAN_ID=$3
    IP_ADDR=$4
    NET_MASK=$5
    GW_IP=$6
    INTERFACE=$7
    TYPE=$8

    REBRIF=`logicalif_to_rebridging $INTERFACE`

    #ifconfig $REBRIF up

    if [ $TYPE = "vlan" ]; then
            ${VCONFIG} add ${REBRIF} ${VLAN_ID}
			NAME=vlan${VLAN_ID}
    else
        if [ $INTERFACE -ne 1 ]; then
			NAME=gre$INTERFACE.$VLAN_ID
		else
			NAME=gre.$VLAN_ID
		fi

		WIRELESS_SUBNET_ADDR_LOCAL=`ifconfig $REBRIF | perl -ne 'if (/.*inet addr:(.+?)\s/) { print $1; }'`;
		#we need to add  a route to the tunnel endpoint through the second interface to prevent
		#the GRE packets from going out through the first interface

		if [ $INTERFACE -ne 1 ]; then
			#ISDHCP=`cat /etc/sysconfig/network-scripts/ifcfg-$SECOND_IF | grep BOOTP | awk -F"=" '{ print $NF }'`               
			[ "`pgrep dhcpcd`" ] && [ "`pgrep dhcpcd | xargs ps | grep -e meru2`" ] && 
			{
				SEC_IF_HAS_DHCP=true
			}

			if [ $SEC_IF_HAS_DHCP = "true" ];then
				GW=`cat /etc/dhcpc/dhcpcd-$SECOND_IF.info | grep GATEWAY | awk -F"=" '{print $NF}'`
			else
				GW=`cat /etc/sysconfig/network-scripts/ifcfg-$SECOND_IF | grep GATEWAY | awk -F"=" '{  print $NF }'`
			fi

			if [ $GW != "" ];then
				if [ `echo $GW | grep "'" ` ]; then
					GW=`echo $GW | awk -F"'" '{print $2}'`
				fi 
				ip route add $GW_IP via $GW dev $REBRIF
			else
				ip route add $GW_IP dev $REBRIF
			fi
		fi

		# check if HA is on and the interface is the first one being used,
		# then use the HA interface: meru:0's ip address, and if it is not up,
		# then loop infinitely and wait for the interface to come up.
		HA_ON=`cat /var/run/heartbeat.pid`

		if [ $HA_ON -ne 0 -a $INTERFACE -eq 1 ];then
			WIRELESS_SUBNET_ADDR_LOCAL=`sed -e "1,83d" -e "85,1000d" /etc/ha.d/haresources | awk -F " " '{ print $2 }'`
		fi

        # Create the tunnel
        ${IPTUNNEL} add $NAME mode gre remote $GW_IP local $WIRELESS_SUBNET_ADDR_LOCAL

        iptables -t mangle -A PREROUTING -i $NAME -j MARK --set-mark $[$VLAN_INDEX+$RT_BASE]
    fi
    
    # insert two RT policy rules
    # formula is RT table1 = VLAN_INDEX + VLAN_INDEX+RT_BASE, 
    #            RT table2 = VLAN_INDEX + VLAN_RANGE +RT_BASE
    HEX_FWMARK0=`printf "%x\n" $[$VLAN_INDEX+$RT_BASE]`
    HEX_FWMARK1=`printf "%x\n" $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE]`

    /sbin/ip rule add fwmark ${HEX_FWMARK0} table $[$VLAN_INDEX+$RT_BASE] pref ${IP_RULE_PREF}
    /sbin/ip rule add fwmark ${HEX_FWMARK1} table $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE] pref ${IP_RULE_PREF}

    #config VLAN interface
	[ $TYPE = "vlan" -a $IP_ADDR != "0.0.0.0" ] && {
	/sbin/ifconfig  ${NAME} ${IP_ADDR} netmask ${NET_MASK} up

	# add default routing entries for each of table talbe
	SUBNET_MASK_CIDR=`ipcalc $IP_ADDR $NET_MASK -p | cut -d= -f 2`
	NETWORK_ID=`ipcalc $IP_ADDR $NET_MASK -n | cut -d= -f 2`

	#grat ARP to tell the whole world..comes in handy in NP1 failover cases
	/sbin/arping -q -c 2 -A -I ${NAME} ${IP_ADDR}

	if [ $VLAN_ID -ne 0 ]; then
		/sbin/ip route add ${NETWORK_ID}/${SUBNET_MASK_CIDR} dev ${NAME} table $[$VLAN_INDEX+$RT_BASE]
	fi

	[ $GW_IP != "0.0.0.0" -a $VLAN_ID -ne 0 ] && {
	/sbin/ip route add via ${GW_IP} dev ${NAME} table $[$VLAN_INDEX+$RT_BASE]
	/sbin/ip route add via ${GW_IP} dev ${NAME} table $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE]
	}

	if [ $VLAN_ID -ne 0 ]; then 
		echo 1 >> /proc/sys/net/ipv4/conf/${NAME}/proxy_arp   
		/sbin/ip route del ${NETWORK_ID}/${SUBNET_MASK_CIDR} dev ${NAME}
	fi
	}

    [ $TYPE = "gre" -a $IP_ADDR != "0.0.0.0" ] && {
		/sbin/ip addr add $IP_ADDR dev $NAME
        /sbin/ip link set $NAME up
        /sbin/ip route add dev ${NAME} table $[$VLAN_INDEX+$RT_BASE]
        /sbin/ip route add dev ${NAME} table $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE]
		#grat ARP to tell the whole world..comes in handy in NP1 failover
		#cases
		/sbin/arping -q -c 2 -A -I ${REBRIF} ${IP_ADDR}
    }

    # add a blackhole routing entry to disallow packets go to other VLAN domains,which could be caused
    # by misconfiguration.


	if [ $VLAN_ID -ne 0 ]; then
		/sbin/ip route add to blackhole 0.0.0.0/0 table $[$VLAN_INDEX+$RT_BASE]
		/sbin/ip route add to blackhole 0.0.0.0/0 table $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE]
	fi
}

terminate() 
{
    VLAN_INDEX=$2
    VLAN_ID=$3
    IP_ADDR=$4
    NET_MASK=$5
    GW_IP=$6
    INTERFACE=$7
    TYPE=$8

    REBRIF=`logicalif_to_rebridging $INTERFACE`


    if [ $TYPE = "vlan" ]; then
			NAME=vlan${VLAN_ID}
            ${VCONFIG} rem ${NAME}
    else
		if [ $INTERFACE -ne 1 ]; then
			NAME=gre$INTERFACE.$VLAN_ID
			ip route del $GW_IP dev $REBRIF
		else
			NAME=gre.$VLAN_ID
		fi

        # Remove the tunnel
        ${IPTUNNEL} del $NAME

        iptables -t mangle -D PREROUTING -i $NAME -j MARK --set-mark $[$VLAN_INDEX+$RT_BASE]
    fi

    #delete 2 RT policy rules for this VLAN 
    
    HEX_FWMARK0=`printf "%x\n" $[$VLAN_INDEX+$RT_BASE]`
    HEX_FWMARK1=`printf "%x\n" $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE]`
    
    /sbin/ip rule del fwmark ${HEX_FWMARK0} table $[$VLAN_INDEX+$RT_BASE] pref ${IP_RULE_PREF} > /dev/null			 
    /sbin/ip rule del fwmark ${HEX_FWMARK1} table $[$VLAN_INDEX+$VLAN_RANGE+$RT_BASE] pref ${IP_RULE_PREF} > /dev/null 		

    /sbin/ip route del default table $[$VLAN_INDEX+$RT_BASE]
    /sbin/ip route del default table $[$VLAN_INDEX+100+$RT_BASE]

    #Other routing entries in each of routing tables gets flushed by kernel automatically
}



case "$1" in
	start)
		start
		;;
	stop)
		stop
		;;
	restart)
		stop
		start
		;;

	vif_up)
    #    	    if [$? -eq 4
		create $1 $2 $3 $4 $5 $6 $7 $8
		;;
	vif_down)
		terminate $1 $2 $3 $4 $5 $6 $7 $8
		;;
	*)
		echo $"Usage: $prog {start|stop|restart|vif_up|vif_down}"
		exit 1
esac

exit 0
