#!/bin/sh
. /lib/functions.sh

#set -x
DEF_INGRESS_IFACE=ifb0
DEF_LAN_IFACE=br-lan

log() {
	logger -t "wrtbwmon" "$@"
}

lock()
{
	while [ -f /tmp/wrtbwmon.lock ]; do
		if [ ! -d /proc/$(cat /tmp/wrtbwmon.lock) ]; then
			log "WARNING : Lockfile detected but process $(cat /tmp/wrtbwmon.lock) does not exist !"
			rm -f /tmp/wrtbwmon.lock
		fi
		sleep 1
	done
	echo $$ > /tmp/wrtbwmon.lock
}

unlock()
{
	rm -f /tmp/wrtbwmon.lock
}

is_number()
{
	# either interger or floating point number is ok
	local input=$1
	case $input in
	''|*[!0-9]*)
		# accept floating point number
		check=$(echo "$1" | sed -n '/^[[:digit:]]\+\.[[:digit:]]\+$/p')
		if [ -n "$check" ]
		then
			return 0
		fi
		;;
	*)
		return 0
		;;
	esac
	return 1
}

bw_blimit_to_kbyte()
{
	input=$1
	input_unit=$2
	is_number "$input" || input=0
	[ -z "$input_unit" ] && input_unit="1"
	if [ "$input_unit" = "2" ] # unit is MB
	then
		input=$(echo "scale=3; $input * 1024" | bc | awk '{printf "%.3f\n", $0}')
	elif [ "$input_unit" = "3"  ] # unit is GB
	then
		input=$(echo "scale=3; $input * 1024 *1024" | bc | awk '{printf "%.3f\n", $0}')
	fi
	echo "$input"
}

bw_str_to_kbyte()
{
	data=$1
	input=$(echo "$data" | cut -d " " -f 1)
	input_unit=$(echo "$data" | cut -d " " -f 2)
	is_number "$input" || input=0
	[ -z "$input_unit" ] && input_unit="KB"
	if [ "$input_unit" = "MB" ]
	then
		input=$(echo "scale=3; $input * 1024" | bc | awk '{printf "%.3f\n", $0}')
	elif [ "$input_unit" = "GB"  ] 
	then
		input=$(echo "scale=3; $input * 1024 *1024" | bc | awk '{printf "%.3f\n", $0}')
	fi
	echo "$input"
}

kbyte_to_bw_str()
{
	# input is in KB
	input=$1
	is_number "$input" || input=0
	if [ $(echo " $input < 1024" | bc) -eq 1  ]
	then
		input_unit="KB"
	elif [ $(echo " $input < 1048576" | bc) -eq 1  ]
	then
		input_unit="MB"
		input=$(echo "scale=3; ${input}/1024" | bc | awk '{printf "%.3f\n", $0}')
	else
		input_unit="GB"
		input=$(echo "scale=3; ${input}/1048576" | bc | awk '{printf "%.3f\n", $0}')
	fi
	echo "$input $input_unit"
}

internet_block()
{
	enable=$1
	iptables -w -S ACCOUNTING_BLOCK > /tmp/iptables.block.$$
	if [ "$enable" = 1 ]
	then
		# insert the block rule
		check=$(cat /tmp/iptables.block.$$ | grep -e "-m comment --comment internet_block -j DROP")
		if [ -z "$check" ]
		then
			iptables -w -I ACCOUNTING_BLOCK -m comment --comment internet_block -j DROP 2>/dev/null
		fi
		uci set monitor.bandwidth.internet_block_status="Blocked"
		uci commit monitor
	else
		# remove the block rule
		count=$(cat /tmp/iptables.block.$$ | grep -e "-m comment --comment internet_block -j DROP" | wc -l)
		for i in $(seq 1 $count)
		do
			iptables -w -D ACCOUNTING_BLOCK -m comment --comment internet_block -j DROP 2>/dev/null
		done
		uci set monitor.bandwidth.internet_block_status="Not Blocked"
		uci commit monitor
	fi

	rm -rf  /tmp/iptables.block.$$
}

throttle_setup()
{
	local ingress_iface="${DEF_INGRESS_IFACE}"
	local _device="${DEF_LAN_IFACE}"

	log "throttle setup $_device $ingress_iface"

	check=$(tc class show dev "$_device")
	[ -n "$check" ] && return

	ifconfig $ingress_iface up

	# Setup Handlers
	tc qdisc del dev "$_device" root 2> /dev/null > /dev/null
	tc qdisc del dev "$_device" ingress 2> /dev/null > /dev/null

	# use new ifb
	tc qdisc del dev "$ingress_iface" root 2> /dev/null > /dev/null

	LAN_IP=$(uci get -q network.lan.ipaddr)

	# limit download (Uplink)
	tc qdisc add dev "$_device" root handle 1: htb default 1 
	tc filter add dev "$_device" parent 1: protocol ip prio 16 u32 match ip dst ${LAN_IP}/24 flowid 1:1
 
	# forward inbound traffic to ifb
	tc qdisc add dev "$_device" ingress
	tc filter add dev "$_device" parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev $ingress_iface

	# limit all inbound traffic via ifb egress
	tc qdisc add dev "$ingress_iface" root handle 1: htb default 1
}

alloc_tc_class()
{
	local max_class=10000
	local allocated=$(uci show userlimits | grep "tc_class=" | cut -d "=" -f 2)
	# class 1 is reserved for default (non-match traffic)
	local allocated="1 $allocated"

	i=1
	while true
	do
		check=$(echo "$allocated" | grep -w "$i")
		if [ -z "$check" ]
		then
			echo "$i"
			return
		fi
		i=$((i + 1))
	done

	return
}

throttle_one_mac()
{
	local cfg=$1
	local mac=$(uci -q get userlimits.${cfg}.mac)
	[ -z "$mac" ] && return

	local up_speed=$(uci -q get userlimits.${cfg}.up_speed)
	local down_speed=$(uci -q get userlimits.${cfg}.down_speed)

	# default limit is 100Mbps
	[ -z "$up_speed" ] && up_speed=100000
	[ -z "$down_speed" ] && down_speed=100000

	local ingress_iface="${DEF_INGRESS_IFACE}"
	local _device="${DEF_LAN_IFACE}"

	local M0=$(echo "$mac" | cut -d ":" -f 1)
	local M1=$(echo "$mac" | cut -d ":" -f 2)
	local M2=$(echo "$mac" | cut -d ":" -f 3)
	local M3=$(echo "$mac" | cut -d ":" -f 4)
	local M4=$(echo "$mac" | cut -d ":" -f 5)
	local M5=$(echo "$mac" | cut -d ":" -f 6)

	local tc_class=$(uci -q get userlimits."${cfg}".tc_class)
	if [ -z "$tc_class" ]
	then
		tc_class=$(alloc_tc_class)
		if [ -z "$tc_class" ]
		then
			log "fail to allocate tc_class for $mac"
			return
		fi
		uci set userlimits."${cfg}".tc_class="$tc_class"
		uci commit userlimits
	fi

	tc class add dev "$_device" parent 1: classid 1:"${tc_class}" htb rate ${down_speed}kbit burst 6k
	tc class add dev "$ingress_iface" parent 1: classid 1:"${tc_class}" htb rate ${up_speed}kbit

	# src MAC filter for ingress interface
	tc filter add dev ${ingress_iface} parent 1: protocol ip prio 5 u32 match u16 0x0800 0xFFFF at -2 match u16 0x${M4}${M5} 0xFFFF at -4 match u32 0x${M0}${M1}${M2}${M3} 0xFFFFFFFF at -8 flowid 1:"${tc_class}"

	# dst MAC filter for LAN interfcae
	tc filter add dev "${_device}" parent 1: protocol ip prio 5 u32 match u16 0x0800 0xFFFF at -2 match u32 0x${M2}${M3}${M4}${M5} 0xFFFFFFFF at -12 match u16 0x${M0}${M1} 0xFFFF at -14 flowid 1:"${tc_class}"
}

unthrottle_one_mac()
{
	local cfg=$1
	local mac=$(uci -q get userlimits.${cfg}.mac)
	[ -z "$mac" ] && return

	local ingress_iface="${DEF_INGRESS_IFACE}"
	local _device="${DEF_LAN_IFACE}"

	local M0=$(echo "$mac" | cut -d ":" -f 1)
	local M1=$(echo "$mac" | cut -d ":" -f 2)
	local M2=$(echo "$mac" | cut -d ":" -f 3)
	local M3=$(echo "$mac" | cut -d ":" -f 4)
	local M4=$(echo "$mac" | cut -d ":" -f 5)
	local M5=$(echo "$mac" | cut -d ":" -f 6)

	local tc_class=$(uci -q get userlimits."${cfg}".tc_class)
	if [ -z "$tc_class" ]
	then
		return
	fi

	while true
	do
		check=$(tc -d filter show dev "$ingress_iface" | grep -e "flowid 1:${tc_class} " | tail -n 1)
		if [ -n "$check" ]
		then
			filter_handle=$(echo "$check" | tail -n 1 | grep -o -e  "fh .* order" | awk '{print $2}')
			tc filter del dev ${ingress_iface} parent 1: handle "$filter_handle" protocol ip prio 5 u32
		else
			break
		fi

	done
	tc class del dev "$ingress_iface" parent 1: classid 1:"${tc_class}"

	while true
	do
		check=$(tc -d filter show dev "$_device" | grep -e "flowid 1:${tc_class} " | tail -n 1)
		if [ -n "$check" ]
		then
			filter_handle=$(echo "$check" | tail -n 1 | grep -o -e  "fh .* order" | awk '{print $2}')
			tc filter del dev ${_device} parent 1: handle "$filter_handle" protocol ip prio 5 u32
		else
			break
		fi

	done
	tc class del dev "$_device" parent 1: classid 1:"${tc_class}"

	uci del userlimits."${cfg}".tc_class
	uci commit userlimits
}

block_one_mac()
{
	local name="$1"
	local mac="$2"
	mac=$(echo "$mac" | tr "[a-z]" "[A-Z]")

	iptables -w -S ACCOUNTING_BLOCK > /tmp/iptables.block.$$

	# check if name can be mapped into ip
	name_ip=$(nslookup "$name" | grep -w "$name" -A 1 | grep "Address 1" | awk '{print $3}')
	if [ -n "$name_ip" ]
	then
		check=$(cat /tmp/iptables.block.$$ | grep -e "-s ${name_ip}/32 -o br-lan -j DROP")
		if [ -z "$check" ]
		then
			iptables -w -I ACCOUNTING_BLOCK -o br-lan -s ${name_ip}/32 -j DROP 2>/dev/null
		fi
	fi

	check=$(cat /tmp/iptables.block.$$ | grep -e "-m mac --mac-source $mac -j DROP")
	if [ -z "$check" ]
	then
		iptables -w -I ACCOUNTING_BLOCK -p ALL -m mac --mac-source $mac -j DROP 2>/dev/null
	fi

	check=$(cat /tmp/iptables.block.$$ | grep -e "-p tcp -m tcp --dport 80 -m mac --mac-source $mac -j DROP")
	if [ -z "$check" ]
	then
		iptables -w -I ACCOUNTING_BLOCK -p tcp --destination-port 80 -m mac --mac-source $mac -j DROP  2>/dev/null
	fi

	check=$(cat /tmp/iptables.block.$$ | grep -e "-p tcp -m tcp --dport 443 -m mac --mac-source $mac -j DROP")
	if [ -z "$check" ]
	then
		iptables -w -I ACCOUNTING_BLOCK -p tcp --destination-port 443 -m mac --mac-source $mac -j DROP  2>/dev/null
	fi

	rm -rf  /tmp/iptables.block.$$
}

unblock_one_mac()
{
	local name="$1"
	local mac="$2"
	mac=$(echo "$mac" | tr "[a-z]" "[A-Z]")
	local i=0

	iptables -w -S ACCOUNTING_BLOCK > /tmp/iptables.block.$$

	# check if name can be mapped into ip
	name_ip=$(nslookup "$name" | grep -w "$name" -A 1 | grep "Address 1" | awk '{print $3}')
	if [ -n "$name_ip" ]
	then
		count=$(cat /tmp/iptables.block.$$ | grep -e "-s ${name_ip}/32 -o br-lan -j DROP" | wc -l)
		for i in $(seq 1 $count)
		do
			iptables -w -D ACCOUNTING_BLOCK -o br-lan -s ${name_ip}/32 -j DROP 2>/dev/null
		done
	fi

	count=$(cat /tmp/iptables.block.$$ | grep -e "-m mac --mac-source $mac -j DROP" | wc -l)
	for i in $(seq 1 $count)
	do
		iptables -w -D ACCOUNTING_BLOCK -p ALL -m mac --mac-source $mac -j DROP
	done

	count=$(cat /tmp/iptables.block.$$ | grep -e "-p tcp -m tcp --dport 80 -m mac --mac-source $mac -j DROP" | wc -l)
	for i in $(seq 1 $count)
	do
		iptables -w -D ACCOUNTING_BLOCK -p tcp --destination-port 80 -m mac --mac-source $mac -j DROP
	done

	count=$(cat /tmp/iptables.block.$$ | grep -e "-p tcp -m tcp --dport 443 -m mac --mac-source $mac -j DROP" | wc -l)
	for i in $(seq 1 $count)
	do
		iptables -w -D ACCOUNTING_BLOCK -p tcp --destination-port 443 -m mac --mac-source $mac -j DROP
	done

	rm -rf  /tmp/iptables.block.$$
}

block_all()
{
	# Block All Wifi Addresses that are not specific configuration
	uci show userlimits | grep "mac=" > /tmp/mac_list.$$
	for mac in $(cat  /proc/net/arp | grep "br-lan" | awk '{print $4}'); do
		check=$(grep -i "$mac" /tmp/mac_list.$$)
		if [ -n "$check" ]
		then
			continue
		fi
		ip=$(grep $mac /tmp/dhcp.leases | awk '{print $3}')
		name=$(grep $mac /tmp/dhcp.leases | awk '{print $4}')
		check=$(iptables -nvL ACCOUNTING_BLOCK | grep -i $mac)
		[ -z "$check" ] && {
			log "Blocking $mac"
			# Lets Block EVERYONE except on LIST ONLY ONCE
			block_one_mac "$name" "$mac"
		}
	done
	rm -rf /tmp/mac_list.$$
}

allow_all()
{
	# Allow All Wifi Addresses that are not specific configuration
	uci show userlimits | grep "mac=" > /tmp/mac_list.$$
	for mac in $(cat  /proc/net/arp | grep "br-lan" | awk '{print $4}'); do
		check=$(grep -i "$mac" /tmp/mac_list.$$)
		if [ -n "$check" ]
		then
			continue
		fi
		ip=$(grep $mac /tmp/dhcp.leases | awk '{print $3}')
		name=$(grep $mac /tmp/dhcp.leases | awk '{print $4}')
		check=$(iptables -w -nvL ACCOUNTING_BLOCK | grep -i $mac)
		[ -n "$check" ] && {
			log "UnBlocking $mac"
			unblock_one_mac "$name" "$mac"
		}
	done
	rm -rf /tmp/mac_list.$$
}

# BLOCK Bandwidth Limit Checker
block_limitcheck() {
	local cfg="$1"
	local usertotal

	config_get _name "$cfg" name
	config_get _mac "$cfg" mac
	config_get _blimit "$cfg" blimit
	config_get _blimitsize "$cfg" blimitsize
	config_get _action "$cfg" action 
	config_get _reset "$cfg" reset

	[ -z "$_action" ] && _action="block"

	#echo ${_mac},800,1000,232323,23000000,$(date "+%d-%m-%Y %H:%M"),$_name > /tmp/usage.db

	if [ "$_reset" = "1" ]; then
		unthrottle_one_mac "$cfg"
		unblock_one_mac "$_name" "$_mac"
		sed "/${_mac//./\.}/ d" /tmp/usage.db > /tmp/usage.new
		mv  /tmp/usage.new /tmp/usage.db # atomic update.
		uci -q set userlimits.$cfg.status="Not Blocked"
		uci delete userlimits.$cfg.reset
		uci commit userlimits
		return
	fi

	if [ "$_action" = "allow" ]; then
		log "User: $_name Mac: $_mac ==> Restrictions Bypassed!!"
		unthrottle_one_mac "$cfg"
		unblock_one_mac "$_name" "$_mac"
		uci -q set userlimits.$cfg.status="Bypassed"
		uci commit userlimits
		return
	fi

	if [ -n "$_mac" ]; then
		mac="$_mac"

		[ -z "$_blimit" ] && _blimit=0
		if [ $_blimitsize -eq 1 ]; then
			usertotal=$(echo "scale=3; ($_blimit * 1)/1" | bc | awk '{printf "%.3f\n", $0}')
		else
			if [ $_blimitsize -eq 2 ]; then
				usertotal=$(echo "scale=3; ($_blimit * 1024)/1" | bc | awk '{printf "%.3f\n", $0}')
			else
				usertotal=$(echo "scale=3; ($_blimit * 1024 *1024)/1" | bc | awk '{printf "%.3f\n", $0}')
			fi
		fi

		log $_name $_mac $_blimit $_blimitsize $_action $_reset

		[ -f "/tmp/usage.db" ] || exit 1
	
		# Lookup MAC total Usage
		LINE=$(grep -i ${_mac} /tmp/usage.db)
		if [ -z "$LINE" ]; then
			return 1
		fi
		PEAKUSAGE_IN=$(echo ${LINE} | cut -f2 -s -d, )
		PEAKUSAGE_OUT=$(echo ${LINE} | cut -f3 -s -d, )
		mactotal=$(echo "scale=3; (${PEAKUSAGE_IN:-0}+${PEAKUSAGE_OUT:-0})/1" | bc | awk '{printf "%.3f\n", $0}')

		#echo $LINE
		#echo $PEAKUSAGE_IN
		#echo $PEAKUSAGE_OUT

		# read table from file
		matchID=$(awk -F "," '/'$_mac'/ {print $5}' /tmp/usage.db)
		log $matchID and $usertotal
		#if [ $(awk -F "," '/'$_mac'/ {print $5}' /tmp/usage.db) -gt ${usertotal} ]; then

		if [ $(echo "$mactotal > $usertotal" | bc) -eq "1"  ]; then
			if [ "$_action" = "block" ]
			then
				log "Blocked $mac for over limit"
				uci -q set userlimits.$cfg.status="Blocked"
				uci commit userlimits
				block_one_mac "$_name" "$_mac"
			else
				log "Throttle $mac for over limit"
				uci -q set userlimits.$cfg.status="Throttled"
				uci commit userlimits
				throttle_one_mac "$cfg"
			fi
		else
			log "Unblocked $mac for under limit"
			unthrottle_one_mac "$cfg"
			unblock_one_mac "$_name" "$_mac"
			uci set userlimits.$cfg.status="Not Blocked"
			uci commit userlimits
		fi
	fi
}

reset_userlimit() {
	local cfg="$1"
	local usertotal

	config_get _name "$cfg" name
	config_get _mac "$cfg" mac
	config_get _blimit "$cfg" blimit
	config_get _blimitsize "$cfg" blimitsize
	config_get _action "$cfg" action
	config_get _reset "$cfg" reset

	if [ -n "$_mac" ]
	then
		unthrottle_one_mac "$cfg"
		unblock_one_mac "$_name" "$_mac"
		sed "/${_mac//./\.}/ d" /tmp/usage.db > /tmp/usage.new
		mv  /tmp/usage.new /tmp/usage.db # atomic update.
		uci -q set userlimits.$cfg.status="Not Blocked"
		uci commit userlimits
	fi
}

detectIF()
{
    uci=`which uci 2>/dev/null`
    if [ -n "$uci" -a -x "$uci" ]; then
	IF=`$uci get network.${1}.ifname`
	[ $? -eq 0 ] && echo $IF && return
    fi
}

detectWAN()
{
    [ -n "$WAN_IF" ] && echo $WAN_IF && return
    wan=$(detectIF wan)
    [ -n "$wan" ] && echo $wan && return
    wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/')
    [ -n "$wan" ] && echo $wan && return
}

case ${1} in
"setup" )
	LAN_IFACE="br-lan"
	#WAN_IFACE=$(uci -q get limit.bandwidth.interface)
	#WAN_IFACE=$(detectWAN)
	#dawsen fix interface
	idP=$(uci get modem.modem1.idP)
        idV=$(uci get modem.modem1.idV)
	WAN_IFACE="wwan0"
	if [ $idV = 1199 -a $idP = 9071 ]; then
                WAN_IFACE="eth2"
        fi

	LAN_IP=$(uci -q get network.lan.ipaddr)
	SERVER_IP=$(echo $LAN_IP  | cut -d . -f 1,2,3).0
	INTERNAL_NETMASK="$SERVER_IP/24"

	# create the ACCOUNTING chains
	iptables -w -N ACCOUNTING_BLOCK 2> /dev/null
	iptables -w -N ACCOUNTING_IN 2> /dev/null
	iptables -w -N ACCOUNTING_OUT 2> /dev/null

	# check if jumps to the ACCOUNTING chains are still at the start of the FORWARD chain
	iptables -w -L FORWARD --line-numbers -n | grep "ACCOUNTING" | grep "^1 "
	if [ $? -ne 0 ]; then
		# remove old jump rules
		iptables -w -D FORWARD $(iptables -w -L FORWARD --line-numbers | grep ACCOUNTING | grep -m 1 -o "[0-9]*")
		while [ $? -eq 0 ]; do
			iptables -w -D FORWARD $(iptables -w -L FORWARD --line-numbers | grep ACCOUNTING | grep -m 1 -o "[0-9]*")
		done
		# insert new jump rules at start of FORWARD chain
		iptables -w -I FORWARD -i ${WAN_IFACE} -j ACCOUNTING_IN
		iptables -w -I FORWARD -o ${WAN_IFACE} -j ACCOUNTING_OUT
		iptables -w -I FORWARD -j ACCOUNTING_BLOCK
	fi

	#For each host in the ARP table
	grep ${LAN_IFACE} /proc/net/arp | while read IP TYPE FLAGS MAC MASK IFACE
	do
		#Add iptables rules (if non existing).
		iptables -w -nL ACCOUNTING_IN | grep "${IP} " > /dev/null
		if [ $? -ne 0 ]; then
			iptables -w -I ACCOUNTING_IN -d ${IP} -s ${INTERNAL_NETMASK} -j RETURN
			iptables -w -I ACCOUNTING_IN -d ${IP} ! -s ${INTERNAL_NETMASK} -j RETURN
		fi

		iptables -w -nL ACCOUNTING_OUT | grep "${IP} " > /dev/null
		if [ $? -ne 0 ]; then
			iptables -w -I ACCOUNTING_OUT -s ${IP} -d ${INTERNAL_NETMASK} -j RETURN
			iptables -w -I ACCOUNTING_OUT -s ${IP} ! -d ${INTERNAL_NETMASK} -j RETURN
		fi
	done

	throttle_setup
	;;
"update" )
	DB="$2"

	[ -z "${DB}" ] && echo "ERROR : Missing Database File Argument 2" && exit 1
	
	# Restore this from a backup if needed
	[ ! -f "${DB}" -a -f /etc/config/usage.db ] && cp /etc/config/usage.db ${DB}

	lock
	
	#Read and reset counters
	iptables -w -L ACCOUNTING_IN -vnxZ -t filter > /tmp/traffic_in_$$.tmp
	iptables -w -L ACCOUNTING_OUT -vnxZ -t filter > /tmp/traffic_out_$$.tmp

	echo 0 > /tmp/download_diff_$$.tmp
	echo 0 > /tmp/upload_diff_$$.tmp

	grep -v "0x0" /proc/net/arp | grep -v 'IP address' | grep br-lan | while read IP TYPE FLAGS MAC MASK IFACE ;
	do
		log "Updating stats for ${IP}"

		# incoming traffic
		grep ${IP} /tmp/traffic_in_$$.tmp | while read PKTS BYTES TARGET PROT OPT IFIN IFOUT SRC DST
      		do
			# check for exclude filter, to distinguish external and internal traffic
			echo "${SRC} ${DST}" | grep "!" > /dev/null
			if [ $? -ne 0 ]; then
				log "Adding internal traffic from ${SRC} to ${DST}"
				if [ "${DST}" = "${IP}" ]
				then
					echo "scale=3; ($BYTES/1024)" | bc | awk '{printf "%.3f\n", $0}' > /tmp/in_$$.tmp
				fi
			else
				log "Adding external traffic from ${SRC} to ${DST}"
				if [ "${DST}" = "${IP}" ]
				then
					echo "scale=3; ($BYTES/1024)" | bc | awk '{printf "%.3f\n", $0}' > /tmp/in_external_$$.tmp
				fi
			fi
		done
		IN=$(cat /tmp/in_$$.tmp)
		[ -z "$IN" ] && IN=0
		IN_EXTERNAL=$(cat /tmp/in_external_$$.tmp)
		[ -z "$IN_EXTERNAL" ] && IN_EXTERNAL=0
		rm -f /tmp/in_$$.tmp
		rm -f /tmp/in_external_$$.tmp

		# outgoing traffic
		grep ${IP} /tmp/traffic_out_$$.tmp | while read PKTS BYTES TARGET PROT OPT IFIN IFOUT SRC DST
		do
			# check for exclude filter, to distinguish external and internal traffic
			echo "${SRC} ${DST}" | grep "!" > /dev/null
			if [ $? -ne 0 ]; then
				log "Adding internal traffic from ${SRC} to ${DST}"
				if [ "${SRC}" = "${IP}" ]
				then
					echo "scale=3; ($BYTES/1024)" | bc | awk '{printf "%.3f\n", $0}' > /tmp/out_$$.tmp
				fi
			else
				log "Adding external traffic from ${SRC} to ${DST}"
				if [ "${SRC}" = "${IP}" ]
				then
					echo "scale=3; ($BYTES/1024)" | bc | awk '{printf "%.3f\n", $0}' > /tmp/out_external_$$.tmp
				fi
			fi
		done
		OUT=$(cat /tmp/out_$$.tmp)
		[ -z "$OUT" ] && OUT=0
		OUT_EXTERNAL=$(cat /tmp/out_external_$$.tmp)
		[ -z "$OUT_EXTERNAL" ] && OUT_EXTERNAL=0
		rm -f /tmp/out_$$.tmp
		rm -f /tmp/out_external_$$.tmp

		log "DEBUG : New traffic for ${MAC} since last update : internal ${IN}k:${OUT}k, external ${IN_EXTERNAL}k:${OUT_EXTERNAL}k"

		LINE=$(grep ${MAC} ${DB})
		if [ -z "${LINE}" ]; then
			log "DEBUG: ${MAC} is a new host!"
			EXTERNAL_IN=0
			EXTERNAL_OUT=0
			INTERNAL_IN=0
			INTERNAL_OUT=0
		else
			EXTERNAL_IN=$(echo ${LINE} | cut -f2 -s -d, )
			EXTERNAL_OUT=$(echo ${LINE} | cut -f3 -s -d, )
			INTERNAL_IN=$(echo ${LINE} | cut -f4 -s -d, )
			INTERNAL_OUT=$(echo ${LINE} | cut -f5 -s -d, )
		fi

		total_download_diff=$(cat /tmp/download_diff_$$.tmp)
		total_upload_diff=$(cat /tmp/upload_diff_$$.tmp)
		echo "scale=3; ($total_download_diff + $IN_EXTERNAL)/1" | bc | awk '{printf "%.3f\n", $0}' > /tmp/download_diff_$$.tmp
		echo "scale=3; ($total_upload_diff + $OUT_EXTERNAL)/1" | bc | awk '{printf "%.3f\n", $0}' > /tmp/upload_diff_$$.tmp

		INTERNAL_IN=$(echo "scale=3; ($INTERNAL_IN + $IN)/1" | bc | awk '{printf "%.3f\n", $0}')
		INTERNAL_OUT=$(echo "scale=3; ($INTERNAL_OUT + $OUT)/1" | bc | awk '{printf "%.3f\n", $0}')
		EXTERNAL_IN=$(echo "scale=3; ($EXTERNAL_IN + $IN_EXTERNAL)/1" | bc | awk '{printf "%.3f\n", $0}')
		EXTERNAL_OUT=$(echo "scale=3; ($EXTERNAL_OUT + $OUT_EXTERNAL)/1" | bc | awk '{printf "%.3f\n", $0}')

		grep -v "${MAC}" ${DB} > /tmp/db_$$.tmp
		mv /tmp/db_$$.tmp ${DB}
		echo ${MAC},${EXTERNAL_IN},${EXTERNAL_OUT},${INTERNAL_IN},${INTERNAL_OUT},$(date "+%d-%m-%Y %H:%M"),${IP} >> ${DB}
	done
	
	total_download_diff=$(cat /tmp/download_diff_$$.tmp)
	total_upload_diff=$(cat /tmp/upload_diff_$$.tmp)
	#Free some memory
	rm -f /tmp/*_$$.tmp

	total_download=$(uci -q get monitor.bandwidth.down)
	[ -z "$total_download" ] && total_download=0
	total_upload=$(uci -q get monitor.bandwidth.up)
	[ -z "$total_upload" ] && total_upload=0
	total=$(uci -q get monitor.bandwidth.total)
	[ -z "$total" ] && total=0

	total_download_kb=$(bw_str_to_kbyte "$total_download")
	total_upload_kb=$(bw_str_to_kbyte "$total_upload")
	total_kb=$(bw_str_to_kbyte "$total")

	total_download_kb=$(echo "scale=3; ($total_download_kb + $total_download_diff)/1" | bc | awk '{printf "%.3f\n", $0}')
	total_upload_kb=$(echo "scale=3; ($total_upload_kb + $total_upload_diff)/1" | bc | awk '{printf "%.3f\n", $0}')
	total_kb=$(echo "scale=3; ($total_kb + $total_download_diff + $total_upload_diff)/1" | bc | awk '{printf "%.3f\n", $0}')

	total_download=$(kbyte_to_bw_str "$total_download_kb")
	total_upload=$(kbyte_to_bw_str "$total_upload_kb")
	total=$(kbyte_to_bw_str "$total_kb")

	uci set monitor.bandwidth.down="$total_download"
	uci set monitor.bandwidth.up="$total_upload"
	uci set monitor.bandwidth.total="$total"
	uci commit monitor

	# check for internet blocking
	internet_block_enabled=$(uci -q get monitor.bandwidth.internet_block_enabled)
	[ -z "$internet_block_enabled" ] && internet_block_enabled=0
	internet_cap_bw=$(uci -q get monitor.bandwidth.internet_cap_bw)
	[ -z "$internet_cap_bw" ] && internet_cap_bw=0
	internet_cap_unit=$(uci -q get monitor.bandwidth.internet_cap_unit)
	[ -z "$internet_cap_unit" ] && internet_cap_unit=0

	if [ "$internet_block_enabled" = "1" ]
	then
		internet_cap_bw_kb=$(bw_blimit_to_kbyte "$internet_cap_bw" "$internet_cap_unit")
		if [ $(echo "$total_kb > $internet_cap_bw_kb" | bc) -eq 1  ]
		then
			log "Internet BW exceeded $total_kb KB > $internet_cap_bw_kb"
			internet_block "1"
		else
			internet_block "0"
		fi
	else
		internet_block "0"
	fi

	unlock
	;;
"backup" )
	[ -f ${2} ] && cp ${2} ${3}
	;;
"reset" )
	totalcalc=$(uci get monitor.bandwidth.oldtot)
	/etc/totcalc $totalcalc
	if [ -f ${2} ]; then
		rm -f ${2}
	fi
	if [ -f ${3} ]; then
		rm -f ${3}
	fi
	uci set monitor.bandwidth.down="0 KB"
	uci set monitor.bandwidth.up="0 KB"
	uci set monitor.bandwidth.total="0 KB"
	uci commit monitor

	# reset all user limit
	config_load userlimits
	config_foreach reset_userlimit user
	;;
"fullreset" )
	rm -rf /tmp/usage.db 
	rm -rf /etc/config/usage.db
	uci set monitor.bandwidth.down="0 KB"
	uci set monitor.bandwidth.up="0 KB"
	uci set monitor.bandwidth.total="0 KB"
	uci set monitor.bandwidth.oldtot="0 KB"
	uci commit monitor
	;;
"test" )
	rm -rf /etc/config/usage.db
	#echo "PREVIOUS MONTH,100000,0,0,0,07-07-2014 20:27,TOTAL" > /tmp/usage.db
	echo "e8:9a:8f:f6:4d:a8,100000,100000,0,0,07-07-2014 20:27,192.168.10.90" >> /tmp/usage.db
	uci set monitor.bandwidth.oldtot="10 MB"
	uci set monitor.bandwidth.down="100.000 MB"
	uci set monitor.bandwidth.up="100.000 MB"
	uci set monitor.bandwidth.total="200.00 MB"
	uci commit monitor
	;;
"writeodl" )
	uci set monitor.bandwidth.oldtot="$2 $3"
	uci commit monitor
	;;
"writedl" )
	uci set monitor.bandwidth.down="$2 $3"
	uci set monitor.bandwidth.up="$4 $5"
	uci set monitor.bandwidth.total="$6 $7"
	uci commit monitor
	;;
"writesdl" )
	uci set monitor.bandwidth.down="$2 $3"
	uci set monitor.bandwidth.up="$4 $5"
	uci set monitor.bandwidth.total="$6 $7"
	uci set monitor.bandwidth.striped="$8"
	uci commit monitor
	;;
"updateandcap" )
	/etc/wrtbwmon update /tmp/usage.db
	/etc/wrtbwmon cap
	;;
"publish" )
	[ -z "${2}" ] && echo "ERROR : Missing argument 2" && exit 1
	[ -z "${3}" ] && echo "ERROR : Missing argument 3" && exit 1
	
	USERSFILE="/etc/dnsmasq.conf"
	[ -f "${USERSFILE}" ] || USERSFILE="/tmp/dnsmasq.conf"
	[ -z "${4}" ] || USERSFILE=${4}
	[ -f "${USERSFILE}" ] || USERSFILE="/dev/null"

	USERSD="/tmp/dhcp.leases"
	# first do some number crunching - rewrite the database so that it is sorted
	lock
	mkdir -p /tmp/www
	touch /tmp/sorted_$$.tmp
	cat ${2} | while IFS=, read MAC PEAKUSAGE_IN PEAKUSAGE_OUT OFFPEAKUSAGE_IN OFFPEAKUSAGE_OUT LASTSEEN
	do
		echo ${PEAKUSAGE_IN},${PEAKUSAGE_OUT},${OFFPEAKUSAGE_IN},${OFFPEAKUSAGE_OUT},${MAC},${LASTSEEN} >> /tmp/sorted_$$.tmp
	done
	unlock


	if [ ! -s "${USERSFILE}" ]; then
       		USERS=$(grep "${MAC}" "${USERSD}" | cut -f4 -s -d" " )
	else
	       	USERS=$(grep "${MAC}" "${USERSFILE}" | cut -f2 -s -d, )
	fi

        # create HTML page
        echo "<html><head><title>Traffic</title><meta http-equiv=\"refresh\" content=\"7\" ><META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"><META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE"><script type=\"text/javascript\">" > ${3}
        echo "function getSize(size) {" >> ${3}
        echo "var prefix=new Array(\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\"); var base=1000;" >> ${3}
        echo "var pos=0; while (size>base) { size/=base; pos++; } if (pos > 2) precision=1000; else precision = 1;" >> ${3}
        echo "return (Math.round(size*precision)/precision)+' '+prefix[pos];}" >> ${3}
        echo "</script></head><body><h1>Total Usage :</h1>" >> ${3}
        echo "<table border="1"><tr bgcolor=silver><th>User</th><th>Peak download</th><th>Peak upload</th><th>Offpeak download</th><th>Offpeak upload</th><th>Last seen</th></tr>" >> ${3}
        echo "<script type=\"text/javascript\">" >> ${3}

        echo "var values = new Array(" >> ${3}
        sort -n /tmp/sorted_$$.tmp | while IFS=, read PEAKUSAGE_IN PEAKUSAGE_OUT OFFPEAKUSAGE_IN OFFPEAKUSAGE_OUT MAC LASTSEEN
        do
                echo "new Array(" >> ${3}
		  USER=${USERS}
 		  [ -z "$USER" ] && USER=${MAC}
                echo "\"${USER}\",${PEAKUSAGE_IN}000,${PEAKUSAGE_OUT}000,${OFFPEAKUSAGE_IN}000,${OFFPEAKUSAGE_OUT}000,\"${LASTSEEN}\")," >> ${3}
        done
        echo "0);" >> ${3}
        # totals
        echo 'var intotal=0;' >> ${3}
        echo 'var outtotal=0;' >> ${3}
        echo 'var inoptotal=0;' >> ${3}
        echo 'var outoptotal=0;' >> ${3}
        echo 'var total=0;' >> ${3}
        echo 'var optotal=0;' >> ${3}
        sort -n /tmp/sorted_$$.tmp | while IFS=, read PEAKUSAGE_IN PEAKUSAGE_OUT OFFPEAKUSAGE_IN OFFPEAKUSAGE_OUT MAC LASTSEEN
        do
            echo "intotal += ${PEAKUSAGE_IN}000;" >> ${3}
            echo "outtotal += ${PEAKUSAGE_OUT}000;" >> ${3}
            echo "inoptotal += ${OFFPEAKUSAGE_IN}000;" >> ${3}
            echo "outoptotal += ${OFFPEAKUSAGE_OUT}000;" >> ${3}
        done
        echo "total += intotal + outtotal;" >> ${3}
        echo "optotal += inoptotal + outoptotal;" >> ${3}

        echo "for (i=0; i < values.length-1; i++) {document.write(\"<tr><td>\");" >> ${3}
        echo "document.write(values[i][0]);document.write(\"</td><td align='right'>\");" >> ${3}
        echo "document.write(getSize(values[i][1]));document.write(\"</td><td align='right'>\");" >> ${3}
        echo "document.write(getSize(values[i][2]));document.write(\"</td><td align='right'>\");" >> ${3}
        echo "document.write(getSize(values[i][3]));document.write(\"</td><td align='right'>\");" >> ${3}
        echo "document.write(getSize(values[i][4]));document.write(\"</td><td>\");" >> ${3}
        echo "document.write(values[i][5]);document.write(\"</td></tr>\");" >> ${3}
        echo "}" >> ${3}
        echo "document.write(\"<tr><td rowspan='2'><b>Totals</b></td>\");" >> ${3}
        echo "document.write(\"<td align='right'>\" + getSize(intotal) + \"</td>\");" >> ${3}
        echo "document.write(\"<td align='right'>\" + getSize(outtotal) + \"</td>\");" >> ${3}
        echo "document.write(\"<td align='right'>\" + getSize(inoptotal) + \"</td>\");" >> ${3}
        echo "document.write(\"<td align='right'>\" + getSize(outoptotal) + \"</td></tr>\");" >> ${3}
        echo 'document.write("<tr>");' >> ${3}
        echo "document.write(\"<td colspan='2' align='center'><b>\" + getSize(total) + \"</b></td>\");" >> ${3}
        echo "document.write(\"<td colspan='2' align='center'><b>\" + getSize(optotal) + \"</b></td>\");" >> ${3}
        echo 'document.write("</tr>");' >> ${3}
        echo "</script></table>" >> ${3}
        echo "<br /><small>This page was generated on `date`</small>" 2>&1 >> ${3}
        echo "</body></html>" >> ${3}

        #Free some memory
        rm -f /tmp/*_$$.tmp
        ;;
"mydata" )
	[ -z "${2}" ] && echo "ERROR : Missing argument 2" && exit 1
	[ -z "${3}" ] && echo "ERROR : Missing argument 3" && exit 1
	
	USERSFILE="/etc/dnsmasq.conf"
	[ -f "${USERSFILE}" ] || USERSFILE="/tmp/dnsmasq.conf"
	[ -z "${4}" ] || USERSFILE=${4}
	[ -f "${USERSFILE}" ] || USERSFILE="/dev/null"

	myinternet_cap_bw=$(uci -q get monitor.bandwidth.internet_cap_bw)
	[ -z "$myinternet_cap_bw" ] && myinternet_cap_bw=0
	myinternet_cap_unit=$(uci -q get monitor.bandwidth.internet_cap_unit)
	[ -z "$myinternet_cap_unit" ] && myinternet_cap_unit=0
	if [ $myinternet_cap_unit -eq 1 ]; then
		myunit="KB";
	elif [ $myinternet_cap_unit -eq 2 ]; then
		myunit="MB";
	elif [ $myinternet_cap_unit -eq 3 ]; then
		myunit="GB";
	else
		myunit="B";
	fi

	
	mydown=$(uci -q get monitor.bandwidth.down)
	myup=$(uci -q get monitor.bandwidth.up)
	mytotal=$(uci -q get monitor.bandwidth.total)

        # create HTML page
        echo "<html><head><title>Traffic</title><meta http-equiv=\"refresh\" content=\"7\" ><META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"><META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">" > ${3}
        echo "</head><body><h1>Data Usage Info:</h1>" >> ${3}
	echo "<h1>Data Allotment : ${myinternet_cap_bw}${myunit}</h1>" >> ${3}
	echo "<h1>Download : ${mydown}</h1>" >> ${3}
	echo "<h1>Upload : ${myup}</h1>" >> ${3}
	echo "<h1>Total Used : ${mytotal}</h1>" >> ${3}
        echo "<br /><small>This page was generated on `date`</small>" 2>&1 >> ${3}
        echo "</body></html>" >> ${3}

        ;;
"cap" )
	# USAGE CAPPING SETTINGS
	config_load userlimits
	config_get_bool isenabled global enabled 0
	[ "$isenabled" = "1" ] || return 0

	config_get_bool ispolicy global policy 0
	# 0 is allow all but block users on list
	# 1 is block all but allow users on list

	# Policy ALLOW then Block users in list
	if [ "$ispolicy" = "0" ]; then
		# search and check each user
		allow_all
		config_foreach block_limitcheck user
	fi

	# Policy BLOCK ALL then allow users in list until they hit their limit
	if [ "$ispolicy" = "1" ]; then
		# search and check each user
		block_all
		config_foreach block_limitcheck user
	fi

	;;
"read" )
	#iptables -L RRDIPT -vnx -t filter > /tmp/traffic.txt
	iptables -L RRDIPT -vnx > /tmp/traffic.tmp
	;;
"remote" )
	# Agent Remote Commands
	/etc/wrtbwmon setup br-lan
	/etc/wrtbwmon update /tmp/usage.db
	/etc/wrtbwmon backup /tmp/usage.db /etc/config/usage.db
	/etc/wrtbwadd
	;;
"throttle")
	throttle_setup
	throttle_one_mac "@user[0]"
	;;
"unthrottle")
	unthrottle_one_mac "@user[0]"
	;;
*)
	echo "Usage : $0 {setup|update|publish} [options...]"
	echo "Options : "
	echo "   $0 setup"
	echo "   $0 read"
	echo "   $0 update database_file [offpeak]"
	echo "   $0 publish database_file path_of_html_report [user_file]"
	echo "Examples : "
	echo "   $0 setup"
	echo "   $0 update /tmp/usage.db offpeak"
	echo "   $0 publish /tmp/usage.db /www/user/usage.htm /jffs/users.txt"
	echo "Note : [user_file] is an optional file to match users with their MAC address"
	echo "       Its format is : 00:MA:CA:DD:RE:SS,username , with one entry per line"
	exit
	;;
esac
