#!/bin/sh

. /lib/functions.sh
. /usr/share/libubox/jshn.sh
. /lib/mcast/common.sh

include /lib/network


CONFFILE=/var/mcpd.conf
PROG_EXE=/usr/sbin/mcpd

proxdevs=""
ethwan="$(jsonfilter -i /etc/board.json -e @.network.wan.device)"


config_snooping_common_params() {
	local protocol="$1"
	echo "${protocol}-default-version $2" >> $CONFFILE
	echo "${protocol}-robustness-value $3" >> $CONFFILE
	echo "${protocol}-max-groups $max_groups" >> $CONFFILE
	echo "${protocol}-max-sources $max_msf" >> $CONFFILE
	echo "${protocol}-max-members $max_members" >> $CONFFILE
	echo "${protocol}-snooping-enable $4" >> $CONFFILE
}

config_mcast_querier_params() {
	local protocol="$1"
	local query_interval=$2
	local q_resp_interval=$3
	local last_mem_q_int=$4

	echo "${protocol}-query-interval $query_interval" >> $CONFFILE
	echo "${protocol}-query-response-interval $q_resp_interval" >> $CONFFILE
	echo "${protocol}-last-member-query-interval $last_mem_q_int" >> $CONFFILE
}

config_snooping_upstream_interface() {
	local snooping_upstream_intf=""

	json_load "$(devstatus $1)"
	itr=1
	json_select bridge-members

	# loop over the bridge and find the device on wan port
	while json_get_var dev $itr; do
		case "$dev" in
			*.*)
				port="$(echo "$dev" | cut -d'.' -f 1)"
				if [ $port == $ethwan ]; then
					ifconfig $dev | grep RUNNING >/dev/null && snooping_upstream_intf="$dev" && break
				fi
				;;
		esac
		itr=$(($itr + 1))
	done
	json_select ..

	# if none of the bridge members are on wan port, set the wan port itself
	if [ -n "$snooping_upstream_intf" ]; then
		echo "upstream-interface $snooping_upstream_intf" >>$CONFFILE
	else
		echo "upstream-interface $ethwan" >>$CONFFILE
	fi
}

config_snooping_on_bridge() {
	local protocol="$1"
	local bcm_mcast_p=1
	echo "${protocol}-snooping-interfaces $2" >> $CONFFILE

	[ "$protocol" == "mld" ] && bcm_mcast_p=2

	for snpif in $2; do
		case "$snpif" in
			br-*)
				# set snooping mode on the bridge
				bcmmcastctl mode -i $snpif -p $bcm_mcast_p -m $3
			;;
		esac
	done
}

config_mcast_proxy_interface() {
	local itr
	local p1="$1"
	local p_enable

	if [ "$p1" == "igmp" ]; then
		p_enable=$igmp_p_enable
	else
		p_enable=$mld_p_enable
	fi

	for proxif in $2; do
		case "$proxif" in
			br-*)
				proxdevs="$proxdevs $proxif"
				echo "upstream-interface $proxif" >>$CONFFILE
			;;
			*)
				ifconfig $proxif | grep RUNNING >/dev/null && proxdevs="$proxdevs $proxif"
			;;
		esac
	done

	if [ $p_enable -eq 1 ]; then
		echo "${p1}-proxy-interfaces $proxdevs" >> $CONFFILE
	fi

	# if proxdevs is empty set the wan port as mcast-interface
	if [ -n "$proxdevs" ]; then
		echo "${p1}-mcast-interfaces $proxdevs" >> $CONFFILE
	else
		echo "${p1}-mcast-interfaces $ethwan" >> $CONFFILE
	fi
}

configure_mcpd_snooping() {
	local protocol="$1"
	local exceptions
	local filter_ip=""
	local fast_leave=0

	# Configure snooping related params
	if [ "$protocol" == "igmp" ]; then
		config_snooping_common_params $protocol $igmp_s_version $igmp_s_robustness $igmp_s_mode
		config_mcast_querier_params $protocol $igmp_s_query_interval $igmp_s_q_resp_interval $igmp_s_last_mem_q_int
		config_snooping_upstream_interface "$igmp_s_iface"
		config_snooping_on_bridge $protocol "$igmp_s_iface" $igmp_s_mode
		exceptions=$igmp_s_exceptions
		fast_leave=$igmp_s_fast_leave
	elif [ "$protocol" == "mld" ]; then
		config_snooping_common_params $protocol $mld_s_version $mld_s_robustness $mld_s_mode
		config_mcast_querier_params $protocol $mld_s_query_interval $mld_s_q_resp_interval $mld_s_last_mem_q_int
		config_snooping_upstream_interface "$mld_s_iface"
		config_snooping_on_bridge $protocol "$mld_s_iface" $mld_s_mode
		exceptions=$mld_s_exceptions
		fast_leave=$mld_s_fast_leave
	fi

	echo "${protocol}-proxy-enable 0" >> $CONFFILE
	echo "${protocol}-fast-leave $fast_leave" >> $CONFFILE

	if [ -n "$exceptions" ]; then
		IFS=" "
		for excp in $exceptions; do
			case $excp in
			*/*)
				tmp="$(ipcalc.sh $excp | grep IP | awk '{print substr($0,4)}')"
				tmp1="$(ipcalc.sh $excp | grep NETMASK | awk '{print substr($0,9)}')"
				filter_ip="$filter_ip $tmp/$tmp1"
				;;
			*)
				filter_ip="$filter_ip $excp"
				;;
			esac
		done
		echo "${protocol}-mcast-snoop-exceptions $filter_ip" >> $CONFFILE
	fi
}

configure_mcpd_proxy() {
	local protocol="$1"
	local fast_leave=0
	local exceptions=""

	# Configure snooping related params
	if [ "$protocol" == "igmp" ]; then
		config_snooping_common_params $protocol $igmp_p_version $igmp_p_robustness $igmp_p_mode
		config_mcast_querier_params $protocol $igmp_query_interval $igmp_q_resp_interval $igmp_last_mem_q_int
		config_mcast_proxy_interface $protocol "$igmp_p_up_interfaces"
		config_snooping_on_bridge $protocol "$igmp_p_down_interfaces" $igmp_p_mode
		fast_leave=$igmp_fast_leave
		exceptions=$igmp_p_exceptions
	elif [ "$protocol" == "mld" ]; then
		config_snooping_common_params $protocol $mld_p_version $mld_p_robustness $mld_p_mode
		config_mcast_querier_params $protocol $mld_query_interval $mld_q_resp_interval $mld_last_mem_q_int
		config_mcast_proxy_interface $protocol "$mld_p_up_interfaces"
		config_snooping_on_bridge $protocol "$mld_p_down_interfaces" $mld_p_mode
		fast_leave=$mld_fast_leave
		exceptions=$mld_p_exceptions
	fi

	# This function will only be hit in case proxy is enabled, so hard coding
	# proxy enable should not be a problem
	echo "${protocol}-proxy-enable 1" >> $CONFFILE
	echo "${protocol}-fast-leave $fast_leave" >> $CONFFILE

	if [ -n "$exceptions" ]; then
		IFS=" "
		for excp in $exceptions; do
			case $excp in
			*/*)
				tmp="$(ipcalc.sh $excp | grep IP | awk '{print substr($0,4)}')"
				tmp1="$(ipcalc.sh $excp | grep NETMASK | awk '{print substr($0,9)}')"
				filter_ip="$filter_ip $tmp/$tmp1"
				;;
			*)
				filter_ip="$filter_ip $excp"
				;;
			esac
		done
		echo "${protocol}-mcast-snoop-exceptions $filter_ip" >> $CONFFILE
	fi
}

disable_snooping() {
	local bcm_mcast_p=$1

	for br in $(brctl show | grep 'br-' | awk '{print$1}' | tr '\n' ' '); do
		bcmmcastctl mode -i $br -p $bcm_mcast_p -m 0 # disable snooping on all bridges
	done
}

configure_mcpd() {
	disable_snooping 1
	disable_snooping 2

	# BCM's mcpd does not allow configuration of proxy and L2 snooping simultaneously, hence
	# here, if proxy is to be configured then the configuration params of snooping are ignored.
	if [ "$igmp_p_enable" == "1" ]; then
		configure_mcpd_proxy igmp
	elif [ "$igmp_s_enable" == "1" ]; then
		configure_mcpd_snooping igmp
	fi

	proxdevs=""
	if [ "$mld_p_enable" == "1" ]; then
		configure_mcpd_proxy mld
	elif [ "$mld_s_enable" == "1" ]; then
		configure_mcpd_snooping mld
	fi
}

setup_mcast_mode() {
	# set the mode at chip to allow both tagged and untagged multicast forwarding
	bs /b/c iptv lookup_method=group_ip_src_ip
}

configure_mcast() {
	rm -f $CONFFILE
	touch $CONFFILE

	# mcpd internally writes max_groups and max_msf, no need to modify
	# here directly
	config_global_params

	read_mcast_snooping_params
	read_mcast_proxy_params

	configure_mcpd
}

validate_params() {
	return 0
}
