#!/bin/sh

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

readonly TEMPFILE="/tmp/snooping_stats_"$$

splitup_ipv6addr() {
	local inaddr="$1"
	local lowaddr=""
	local hiaddr=""
	local subaddr=""
	local outaddr=""

	OIFS=$IFS
	IFS=":"
	for subaddr in $inaddr; do
		loaddr="$(printf "%x\n" 0x$(echo -n "$subaddr" | cut -b5-8))"
		hiaddr="$(printf "%x\n" 0x$(echo -n "$subaddr" | cut -b1-4))"
		if [ -z "$outaddr" ]; then
			outaddr="${hiaddr}:${loaddr}"
		else
			outaddr="${outaddr}:${hiaddr}:${loaddr}"
		fi
	done
	IFS=$OIFS

	echo "$outaddr" | sed -e 's/0000/0/g' -e 's/00/0/g' -e 's/000/0/g'
}

meld_files() {
	local type="$1"

	if [ "$type" = "mld" ]; then
		cat "/proc/net/${type}_snooping" | awk -F' ' '{ print $1 " " $2 " " $3 " " $4 " " $5 " " $6 " " $7 " " $8 " NULL " $9 " " $10 " " $11 " " $12 " " $13 " " $12 }' >> "$TEMPFILE"
	else
		cat "/proc/net/${type}_snooping" >> "$TEMPFILE"
	fi
}

read_snooping_file() {
	local mcast_addrs=""
	local ifaces=""

	while read line; do
	# reading each line
		case $line in
		br-*)
			found_iface=0
			snoop_iface="$(echo $line | awk -F ' ' '{ print $1 }')"
			if [ -z "$ifaces" ]; then
				ifaces="$snoop_iface"
				continue
			fi

			IFS=" "
			for ifx in $ifaces; do
				if [ $ifx == $snoop_iface ]; then
					found_iface=1
					break
				fi
			done

			if [ $found_iface -eq 0 ]; then
				ifaces="$ifaces $snoop_iface"
				continue
			fi
			;;
		esac
	done < "$TEMPFILE"

	while read line; do
	# reading each line
		case $line in
		br-*)
			found_ip=0
			grp_ip="$(echo $line | awk -F ' ' '{ print $10 }')"

			if [ -z "$mcast_addrs" ]; then
				mcast_addrs="$grp_ip"
				continue
			fi

			IFS=" "
			for ip_addr in $mcast_addrs; do
				if [ $ip_addr == $grp_ip ]; then
					found_ip=1
					break
				fi
			done

			if [ $found_ip -eq 0 ]; then
				mcast_addrs="$mcast_addrs $grp_ip"
				continue
			fi
			;;
		esac
	done < "$TEMPFILE"

	IFS=" "
	for intf in $ifaces; do
		json_add_object ""
		json_add_string "interface" "$intf"
		json_add_array "groups"
		IFS=" "
		for gip_addr in $mcast_addrs; do
			grp_obj_added=0
			while read line; do
			# reading each line
				case $line in
				br-*)
					snoop_iface="$(echo $line | awk -F ' ' '{ print $1 }')"
					if [ "$snoop_iface" != "$intf" ]; then
						continue
					fi
					grp_ip="$(echo $line | awk -F ' ' '{ print $10 }')"
					if [ "$grp_ip" != "$gip_addr" ]; then
						continue
					fi
					if [ $grp_obj_added -eq 0 ]; then
						json_add_object ""
						if [ -n "$(echo $gip_addr | grep -oE "^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$")" ]; then
							gip="$(ipcalc.sh $gip_addr | grep IP | awk '{print substr($0,4)}')"
						else
							gip_addr=$(splitup_ipv6addr "$gip_addr")
							gip="$(echo $gip_addr | grep -oE '^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$')"
						fi
						json_add_string "groupaddr" "$gip"
						json_add_array "clients"
						grp_obj_added=1
					fi

					json_add_object ""
					host_ip="$(echo $line | awk -F ' ' '{ print $14 }')"
					if [ -n "$(echo $host_ip | grep -oE "^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$")" ]; then
						h_ip="$(ipcalc.sh $host_ip | grep IP | awk '{print substr($0,4)}')"
					else
						host_ip=$(splitup_ipv6addr "$host_ip")
						h_ip="$(echo $host_ip | grep -oE '^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$')"
					fi
					json_add_string "ipaddr" "$h_ip"
					src_port="$(echo $line | awk -F ' ' '{ print $2 }')"
					json_add_string "device" "$src_port"
					timeout="$(echo $line | awk -F ' ' '{ print $15 }')"
					json_add_int "timeout" "$timeout"
					json_close_object #close the associated device object
					;;
				esac
			done < "$TEMPFILE"
			if [ $grp_obj_added -eq 1 ]; then
				json_close_array #close the associated devices array
				json_close_object # close the groups object
			fi
		done # close the loop for group addresses
		json_close_array #close the groups array
		json_close_object # close the snooping object
	done # close the loop for interfaces
}

read_mcast_stats() {
	echo -n > "$TEMPFILE"

	json_init
	json_add_array "snooping"
	meld_files "igmp"
	meld_files "mld"
	read_snooping_file
	json_close_array # close the snooping array
	json_dump

	rm -f "$TEMPFILE"
}

case "$1" in
	list)
		echo '{ "stats":{} }'
		;;
	call)
		case "$2" in
			stats)
				out="$(read_mcast_stats)"
				if [ -z "${out}" ]; then
					echo '{}'
				else
					echo "${out}"
				fi
				;;
		esac
		;;
esac
