#!/bin/sh
# add ip rule from qos uci

FWD_POLICY=""

init_ip_rule() {
        FWD_POLICY=""
}

ip_rule_match_inif() {
        FWD_POLICY="$FWD_POLICY iif $1"
}

ip_rule_match_proto() {
        FWD_POLICY="$FWD_POLICY ipproto $1"
}

ip_rule_match_dest_port() {
        FWD_POLICY="$FWD_POLICY dport $1"
}

ip_rule_match_src_port() {
        FWD_POLICY="$FWD_POLICY sport $1"
}

ip_rule_match_dest_ip() {
        FWD_POLICY="$FWD_POLICY to $1"
}

ip_rule_match_src_ip() {
        FWD_POLICY="$FWD_POLICY from $1"
}

ip_rule_match_dest_port_range() {
        FWD_POLICY="$FWD_POLICY dport $1-$2"
}

ip_rule_match_src_port_range() {
        FWD_POLICY="$FWD_POLICY sport $1-$2"
}

ip_rule_match_fwmark() {
        FWD_POLICY="$FWD_POLICY fwmark $1"
}

ip_rule_handle_match_tos() {
	local dscp="$2"
	local IPTOS_LOWDELAY="0x10"
	local tos_val="$((dscp<<2))"

	# ip rule not accept beyond 0x10, to handle further value mark the tos
	# value through iptable and route with that marked value by fwmark
	# in ip rule
	if [ "$((tos_val))" -gt "$((IPTOS_LOWDELAY))" ]; then
		handle_iptables_rules $1 $(ip_rule_get_converted_tos $tos_val)
		ip_rule_match_fwmark  $(printf 0x%x $tos_val)
	else
		FWD_POLICY="$FWD_POLICY tos $(printf %x $tos_val)"
		if [ -n "$3" ]; then
			ip_rule_match_fwmark  $3
		fi
	fi
}

handle_ip_rule() {
	cid=$1
	fwding_policy=$2

	init_ip_rule

	# get uci value for selector/match
	config_get dest_ip "$cid" "dest_ip"
	config_get src_ip "$cid" "src_ip"
	config_get ifname "$cid" "ifname"
	config_get proto "$cid" "proto"
	config_get dscp "$cid" "dscp_filter"
	config_get fwmark "$cid" "traffic_class"
	config_get dest_port "$cid" "dest_port"
	config_get dest_port_range "$cid" "dest_port_range"
	config_get src_port "$cid" "src_port"
	config_get src_port_range "$cid" "src_port_range"

	# forming selector/match for rule
	[ -n "$ifname" ] && ip_rule_match_inif $ifname

	[ -n "$proto" ] && ip_rule_match_proto $proto

	if [ -n "$src_port" -a -z "$src_port_range" ]; then
		ip_rule_match_src_port $src_port
	fi

	if [ -n "$dest_port" -a -z "$dest_port_range" ]; then
		ip_rule_match_dest_port $dest_port
	fi

	[ -n "$src_ip" ] && ip_rule_match_src_ip $src_ip

	[ -n "$dest_ip" ] && ip_rule_match_dest_ip $dest_ip

	if [ -n "$dest_port" -a -n "$dest_port_range" ]; then
		ip_rule_match_dest_port_range $dest_port $dest_port_range
	fi

	if [ -n "$src_port" -a -n "$src_port_range" ]; then
		ip_rule_match_src_port_range $src_port $src_port_range
	fi

	if [ -n "$dscp" ]; then
		# If tos and fwmark configured then fwmark be igroned/skipped
		# in the case of tos value greater than 0x10 and if tos value
	        # less than 0x10 then both tos and fwmark then both configuration
		#considered/applied for ip rule.
		ip_rule_handle_match_tos $cid $dscp $fwmark
	elif [ -n "$fwmark" ]; then
		ip_rule_match_fwmark  $fwmark
	fi

	# forming full ip rule
	if [ -n "$FWD_POLICY" ]; then
		echo "ip rule add $FWD_POLICY table $fwding_policy" >> /tmp/qos/classify.iprule
		echo "ip rule del $FWD_POLICY table $fwding_policy" >> /tmp/qos/classify.del_iprule
	fi
}

flush_ip_rule() {
	if [ -s "/tmp/qos/classify.del_iprule" ]; then
		sh /tmp/qos/classify.del_iprule
		rm -f /tmp/qos/classify.del_iprule
	fi
	touch /tmp/qos/classify.del_iprule
}
