#!/bin/sh /etc/rc.common
# Copyright (c) 2014 The Linux Foundation. All rights reserved.
# Copyright (C) 2010-2014 OpenWrt.org
. /lib/zone/zone_api.sh

START=99
STOP=10

SERVICE_DAEMONIZE=1
SERVICE_WRITE_PID=1
CONF_FILE="/etc/improxy.conf"
VNET_CONF_FILE="/etc/improxy.conf"
#VNET_CONF_FILE="/etc/improxyvnet.conf"
PROG="/usr/sbin/vnete /usr/sbin/improxy"
CONFIG_IMPROXY="/etc/config/improxy"
MAXDOWNSTREAM=31
readonly LOCKFILE="/tmp/improxy.lock"
readonly FD=$(ls -l /proc/$$/fd | sed -n '$p' | awk '{print $9}')
readonly LOCKFD=$(( ${FD}+1 ))

lock() {
	eval "exec $LOCKFD>${LOCKFILE}"
	flock -x $LOCKFD
}

unlock() {
	flock -u $LOCKFD
	eval "exec ${LOCKFD}>&-"
}

multilan() {
	local m=$(uci -c /etc/profile.d get profile.@global[0].multilan)
	if [ $m == 1 ]; then
		return 0
	else
		return 1
	fi
}

improxy_pinstance() {
	local upstream downstream
	config_load iptv
	#default WAN
	config_get igmp_interface "iptv" igmp_interface "WAN1"
	wan_interface=$(zone_get_wan_ifaces $igmp_interface)
	for wan_interface_eth in ${wan_interface}
	do
		if ((expr match "$wan_interface_eth" ".*_eth") || (expr match "$wan_interface_eth" ".*_poe")); then
			upstream=$(zone_get_device_byif $wan_interface_eth)
			break
		fi
	done
	echo -e "upstream \t$upstream" >>$CONF_FILE
	
	#default LAN
	#config_load network
	#config_get downstream lan ifname
	#echo -e "downstream \t$downstream" >>$CONF_FILE
}
mld_upstream_add() {
        local cfg="$1"
        local iface=`echo ${2} | tr '[A-Z]' '[a-z]'`
        local v6_end="_v6"
        local wan_type
        local mld_upstream
        iface=$iface$v6_end

        [ ${#cfg} -le 3 -o "$cfg" != "$iface" ] && {
                return 0
        }

        config_get wan_type "$cfg" wan_type
        if [ "x$wan_type" = "xpppoev6" ]; then
                config_get pppshare "$cfg" pppshare
		if [ "x$pppshare" = "x1" ]; then
			config_get parent "$cfg" parent
			[ "x$parent" = "x" ] && {
				echo "mld_upstream is invalid, error" > /dev/console
				return 0
			}
			mld_upstream="pe-""$parent"
		else
                	mld_upstream="pe-""$iface"
		fi
        elif [ "x$wan_type" = "x6to4" -o "x$wan_type" = "xpassthrough" ]; then
		echo "mld not supported by cur ipv6 mode" > /dev/console
		return 0
        else
                mld_upstream=$(uci get network.$cfg.ifname)
                #config_get mld_upstream "$cfg" ifname
        fi

        [ "x$mld_upstream" = "x" ] && {
                return 0
        }
        echo "mld add upstream: $mld_upstream success" > /dev/console
        echo -e "mld \tenable \tversion \t$mld_version" >>$CONF_FILE
        echo -e "mld_upstream \t$mld_upstream" >>$CONF_FILE
}

improxy_pinstance_v6() {
	config_load iptv
	#default WAN
	config_get mld_interface "mld" mld_interface "WAN1"
	config_load network
	config_foreach mld_upstream_add interface $mld_interface
}

update_improxy_config()
{
	local cfg="$1"
	[ "$cfg" = "vwan" ] && {
		return 0
	}
	config_get ifname "$cfg" ifname
	config_get name "$cfg" zone
	exist=`cat $VNET_CONF_FILE | grep $ifname`
	if [ -n "$exist" ]; then
		uci add_list improxy.vifs.name=$name 
	fi
}

vnet_downstream_add() {
	local cfg="$1"
	[ "$cfg" = "vwan" ] && {
		return 0
	}
	config_get downstream "$cfg" ifname
	config_get name "$cfg" zone
	#加入过组播的lan直接写入VNET_CONF_FILE，否则按照vnetwork顺序写入待确认列表
	exist=`cat $CONFIG_IMPROXY | grep $name`
	if [ -n "$exist" ]; then
		[ "$total_downstream" -eq $MAXDOWNSTREAM ] &&{
			return 0
		}
		echo -e "downstream \t$downstream" >>$VNET_CONF_FILE
		echo -e "mld_downstream \t$downstream" >>$VNET_CONF_FILE
		total_downstream=$((total_downstream + 1))
	else
		unconfirm_list="${unconfirm_list} ${downstream}"
	fi
}


improxy_vnet_pinstance() {
	local upstream downstream
	local unconfirm_list=""
	local total_downstream=0
	config_load vnetwork
	config_get upstream vwan ifname
	#echo -e "upstream \t$upstream" >>$VNET_CONF_FILE
	config_foreach vnet_downstream_add vinterface
	#遍历待确认列表，逐一写入VNET_CONF_FILE
	for downstream in ${unconfirm_list} ; do 
		[ "$total_downstream" -eq $MAXDOWNSTREAM ] &&{
			break
		}
		echo -e "downstream \t$downstream" >>$VNET_CONF_FILE
		echo -e "mld_downstream \t$downstream" >>$VNET_CONF_FILE
		total_downstream=$((total_downstream + 1))
	done
	#更新improxy的vifs配置，保存当前加入组播的lan
	uci -q delete improxy.vifs
	uci set improxy.vifs=zone
	config_foreach update_improxy_config vinterface
	uci commit improxy
	/lib/cfg_save/config.sh save
}

igmp_add_fw_rules() {
	local r1 r2 r3 r4 r5 r6
	local ipset1
	
	r1=$(fw list 4 f INPUT|grep "\-p igmp")
	[ -z "$r1" ] && fw add 4 f INPUT ACCEPT ^ { -p igmp }
	
	ipset1=$(ipset list | grep "improxy_ip_group")
	[ -z "$ipset1" ] && ipset create improxy_ip_group hash:ip
	
	r2=$(iptables -t mangle -nL PREROUTING -w|grep "\improxy_ip_group dst")
	[ -z "$r2" ] && iptables -t mangle -w -A PREROUTING -p udp -m set --match-set improxy_ip_group dst -j ACCEPT 
	
	r3=$(iptables -t mangle -nL PREROUTING -w|grep "224.0.0.0/4")
	[ -z "$r3" ] && iptables -t mangle -w -A PREROUTING -p udp -d 224.0.0.0/4 -j DROP 

	r4=$(fw list 4 f OUTPUT|grep "\-p igmp")
	[ -z "$r4" ] && fw add 4 f OUTPUT ACCEPT ^ { -p igmp }
	
	r5=$(fw list 4 f  OUTPUT|grep "\-d 224.0.0.0/4")
	[ -z "$r5" ] && fw add 4 f  OUTPUT ACCEPT ^ { -p udp -d 224.0.0.0/4 }

	r6=$(fw list 4 f FORWARD|grep "\-d 224.0.0.0/4")
	[ -z "$r6" ] && fw add 4 f FORWARD ACCEPT ^ { -p udp -d 224.0.0.0/4 }
}


igmp_add_fw_rules_v6() {
	local r1 r2 r3 r4 r5 r6
	local ipset1
	
	r1=$(fw list 6 f INPUT|grep "\-p ipv6-icmp")
	[ -z "$r1" ] && fw add 6 f INPUT ACCEPT ^ { -p icmpv6 }
	
	# ipv6添加需要指定 family inet6
	ipset1=$(ipset list | grep "mldproxy_ip_group")
	[ -z "$ipset1" ] && ipset create mldproxy_ip_group hash:ip family inet6
	
	r2=$(ip6tables -t mangle -nL PREROUTING -w|grep "\mldproxy_ip_group dst")
	[ -z "$r2" ] && ip6tables -t mangle -w -A PREROUTING -p udp -m set --match-set mldproxy_ip_group dst -j ACCEPT 
	
	r3=$(ip6tables -t mangle -nL PREROUTING -w|grep -i "ff00::/8")
	[ -z "$r3" ] && ip6tables -t mangle -w -A PREROUTING -p udp -d ff00::/8 -j DROP 

	r4=$(fw list 6 f OUTPUT|grep "\-p ipv6-icmp")
	[ -z "$r4" ] && fw add 6 f OUTPUT ACCEPT ^ { -p icmpv6 }
	
	r5=$(fw list 6 f  OUTPUT|grep -i "\-d ff00::/8")
	[ -z "$r5" ] && fw add 6 f  OUTPUT ACCEPT ^ { -p udp -d ff00::/8 }

	r6=$(fw list 6 f FORWARD|grep -i "\-d ff00::/8")
	[ -z "$r6" ] && fw add 6 f FORWARD ACCEPT ^ { -p udp -d ff00::/8 }
}

igmp_del_fw_rules() {
	fw del 4 f INPUT ACCEPT { -p igmp }
	iptables -t mangle -w -D PREROUTING -p udp -d 224.0.0.0/4 -j DROP 
	iptables -t mangle -w -D PREROUTING -p udp -m set --match-set improxy_ip_group dst -j ACCEPT 
	fw del 4 f OUTPUT ACCEPT { -p igmp }
	fw del 4 f OUTPUT ACCEPT { -p udp -d 224.0.0.0/4 }
	fw del 4 f FORWARD ACCEPT { -p udp -d 224.0.0.0/4 }
	ipset destroy improxy_ip_group
}

igmp_del_fw_rules_v6() {
	fw del 6 f INPUT ACCEPT { -p icmpv6 }
	ip6tables -t mangle -w -D PREROUTING -p udp -d ff00::/8 -j DROP 
	ip6tables -t mangle -w -D PREROUTING -p udp -m set --match-set mldproxy_ip_group dst -j ACCEPT 
	fw del 6 f OUTPUT ACCEPT { -p icmpv6 }
	fw del 6 f OUTPUT ACCEPT { -p udp -d ff00::/8 }
	fw del 6 f FORWARD ACCEPT { -p udp -d ff00::/8 }
	# ipv6删除通用
	ipset destroy mldproxy_ip_group
}

_start() {
#	local status
#	config_load network
	local igmp_enable 
	local igmp_version
	local igmp_proxy_max
	config_load iptv
	echo "" > $CONF_FILE
#	config_get status "lan" igmp_snooping
	config_get igmp_enable "iptv" igmp_enable 

	igmp_proxy_max=`uci -c /etc/profile.d get profile.@iptv[0].igmp_proxy_max`

#	if [ "$status" = "1" -a "$iptv_on" = "on" ]; then
	if [ "$igmp_enable" = "on" ]; then
		config_get igmp_version "iptv" igmp_version "2"
		echo $igmp_version > /proc/sys/net/ipv4/conf/all/force_igmp_version
		echo $igmp_proxy_max > /proc/sys/net/ipv4/igmp_max_memberships

		igmp_add_fw_rules		
		echo -e "igmp \tenable \tversion \t$igmp_version" >$CONF_FILE
		# echo -e "mld \tenable" >>$CONF_FILE
		
		#if (multilan); then
			#echo -e "igmp \tenable \tversion \t$igmp_version" >$VNET_CONF_FILE
			# echo -e "mld \tenable" >>$VNET_CONF_FILE
		#fi
		
		improxy_pinstance
		
		#service_start /usr/sbin/improxy -c $CONF_FILE -p "/tmp/improxy.pid"
		
		#if (multilan); then
			#service_start $PROG -c $VNET_CONF_FILE -p "/tmp/improxyvnet.pid"
		#fi
	else
		igmp_del_fw_rules
		echo 2 > /proc/sys/net/ipv4/conf/all/force_igmp_version
	fi
	# ipv6
	local mld_enable
	local mld_version
	config_get mld_enable "mld" mld_enable "off"

	if [ "$mld_enable" = "on" ]; then
		config_get mld_version "mld" mld_version "1"
		echo $mld_version > /proc/sys/net/ipv6/conf/all/force_mld_version
		
		igmp_add_fw_rules_v6
		improxy_pinstance_v6
	else
		igmp_del_fw_rules_v6
		echo 0 > /proc/sys/net/ipv6/conf/all/force_mld_version
	fi

	if [ "$mld_enable" = "on" -o   "$igmp_enable" = "on" ]; then
			if (multilan); then
				improxy_vnet_pinstance
			fi
			service_start /usr/sbin/improxy -c $CONF_FILE -p "/tmp/improxy.pid"
	fi
	
	return 0
}

_stop() {	
	service_stop /usr/sbin/improxy
	if (multilan); then
		#service_stop $PROG
		[ -f /tmp/improxyvnet.pid ] && {
			kill $(cat /tmp/improxyvnet.pid)
		}
	fi
	return 0
}

stop() {
	lock
	_stop
	unlock
}

start() {
	lock
	_start
	unlock
}

restart() {
	lock
	_stop
	_start
	unlock
}
reload(){
	local enable=`uci get iptv.iptv.igmp_enable`
	if [ "$enable" = "on" ]; then
		service_stop /usr/sbin/improxy
		local igmp_version=`uci get iptv.iptv.igmp_version`
		echo -e "igmp \tenable \tversion \t$igmp_version" >$CONF_FILE
		
		improxy_pinstance
		improxy_vnet_pinstance
		service_start /usr/sbin/improxy -c $CONF_FILE -p "/tmp/improxy.pid"
	fi
}
