#!/bin/sh

# Initialize library
MOD_CP_LIB=/opt/captive_portal/usr/libexec/functions
[ -f "$MOD_CP_LIB" ] || exit 2
. $MOD_CP_LIB

# Prepare environment
get_public_iface_info

QOS_WAN_IF=$WAN_IF
QOS_WAN_MARK=0xA00000
QOS_WAN_CHAIN=$MOD_CP_NAME-pre-qos
QOS_ID_DF=999

# Prepare WLAN0 or ETH0 settings
if [ -n "$PUBLIC_IF1_NAME" ]; then
  QOS1_LAN_IF=$PUBLIC_IF1_NAME
  QOS1_LAN_MARK=0xA10000
  QOS1_LAN_CHAIN=$MOD_CP_NAME-qos1
  QOS1_LAN_NETWORK=${PUBLIC_IF1_NETWORK%0}
  QOS1_ID_ME=${PUBLIC_IF1_IP#$QOS1_LAN_NETWORK}
  QOS1_ID_ME=$((QOS1_ID_ME+1000))
fi
if [ -n "$PUBLIC_IF2_NAME" ]; then
  QOS2_LAN_IF=$PUBLIC_IF2_NAME
  QOS2_LAN_MARK=0xA20000
  QOS2_LAN_CHAIN=$MOD_CP_NAME-qos2
  QOS2_LAN_NETWORK=${PUBLIC_IF2_NETWORK%0}
  QOS2_ID_ME=${PUBLIC_IF2_IP#$QOS2_LAN_NETWORK}
  QOS2_ID_ME=$((QOS2_ID_ME+2000))
fi
if [ -n "$PUBLIC_IF3_NAME" ]; then
  QOS3_LAN_IF=$PUBLIC_IF3_NAME
  QOS3_LAN_MARK=0xA30000
  QOS3_LAN_CHAIN=$MOD_CP_NAME-qos3
  QOS3_LAN_NETWORK=${PUBLIC_IF3_NETWORK%0}
  QOS3_ID_ME=${PUBLIC_IF3_IP#$QOS3_LAN_NETWORK}
  QOS3_ID_ME=$((QOS3_ID_ME+3000))
fi
# Default QoS speed values
if [ "$3" = "restricted" ]; then
  RATE_DL=$MOD_CP_QOS_VOLUME_CUST_DLS
  RATE_UL=$MOD_CP_QOS_VOLUME_CUST_ULS
else
  if [ "$MOD_CP_QOS_RATE_ENABLED" = "1" ]; then
    RATE_DL=$MOD_CP_QOS_RATE_CUST_DL
    RATE_UL=$MOD_CP_QOS_RATE_CUST_UL
  fi
fi

# Execute command
case "$1" in
    start|restart)
        # Stop previous QoS service
        $0 stop >/dev/null 2>&1
        if [ "$MOD_CP_QOS_RATE_ENABLED" != "1" ] && [ "$MOD_CP_QOS_UPDOWN_SPEED_ENABLED" != "1" ]; then
          exit 0
        fi
        [ -n "$QOS_WAN_IF" ] || exit 3
        # Set default values
        if [ "$MOD_CP_QOS_RATE_ENABLED" = "0" ]; then
          MOD_CP_QOS_RATE_ROOT_DL=100000
          MOD_CP_QOS_RATE_ROOT_UL=100000
        fi
        [ -n "$MOD_CP_QOS_RATE_ROOT_DL" ] || MOD_CP_QOS_RATE_ROOT_DL=100000
        [ -n "$MOD_CP_QOS_RATE_ROOT_UL" ] || MOD_CP_QOS_RATE_ROOT_UL=100000
        # Upload
        tc qdisc add dev $QOS_WAN_IF handle 1: root htb default $QOS_ID_DF
        iptables -t mangle -N $QOS_WAN_CHAIN
        if [ -n "$QOS1_LAN_IF" ]; then
          # Download
          tc qdisc add dev $QOS1_LAN_IF handle 1: root htb default $QOS_ID_DF
          tc class add dev $QOS1_LAN_IF classid 1:$QOS1_ID_ME parent 1: htb rate ${MOD_CP_QOS_RATE_ROOT_DL}kbit ceil ${MOD_CP_QOS_RATE_ROOT_DL}kbit
          iptables -t mangle -N $QOS1_LAN_CHAIN
          iptables -t mangle -I POSTROUTING -o $QOS1_LAN_IF -j $QOS1_LAN_CHAIN
          # Upload
          tc class add dev $QOS_WAN_IF classid 1:$QOS1_ID_ME parent 1: htb rate ${MOD_CP_QOS_RATE_ROOT_UL}kbit ceil ${MOD_CP_QOS_RATE_ROOT_UL}kbit
          iptables -t mangle -I PREROUTING -i $QOS1_LAN_IF -j $QOS_WAN_CHAIN
        fi
        if [ -n "$QOS2_LAN_IF" ]; then
          # Download
          tc qdisc add dev $QOS2_LAN_IF handle 1: root htb default $QOS_ID_DF
          tc class add dev $QOS2_LAN_IF classid 1:$QOS2_ID_ME parent 1: htb rate ${MOD_CP_QOS_RATE_ROOT_DL}kbit ceil ${MOD_CP_QOS_RATE_ROOT_DL}kbit
          iptables -t mangle -N $QOS2_LAN_CHAIN
          iptables -t mangle -I POSTROUTING -o $QOS2_LAN_IF -j $QOS2_LAN_CHAIN
          # Upload
          tc class add dev $QOS_WAN_IF classid 1:$QOS2_ID_ME parent 1: htb rate ${MOD_CP_QOS_RATE_ROOT_UL}kbit ceil ${MOD_CP_QOS_RATE_ROOT_UL}kbit
          iptables -t mangle -I PREROUTING -i $QOS2_LAN_IF -j $QOS_WAN_CHAIN
        fi
        if [ -n "$QOS3_LAN_IF" ]; then
          # Download
          tc qdisc add dev $QOS3_LAN_IF handle 1: root htb default $QOS_ID_DF
          tc class add dev $QOS3_LAN_IF classid 1:$QOS3_ID_ME parent 1: htb rate ${MOD_CP_QOS_RATE_ROOT_DL}kbit ceil ${MOD_CP_QOS_RATE_ROOT_DL}kbit
          iptables -t mangle -N $QOS3_LAN_CHAIN
          iptables -t mangle -I POSTROUTING -o $QOS3_LAN_IF -j $QOS3_LAN_CHAIN
          # Upload
          tc class add dev $QOS_WAN_IF classid 1:$QOS3_ID_ME parent 1: htb rate ${MOD_CP_QOS_RATE_ROOT_UL}kbit ceil ${MOD_CP_QOS_RATE_ROOT_UL}kbit
          iptables -t mangle -I PREROUTING -i $QOS3_LAN_IF -j $QOS_WAN_CHAIN
        fi
        exit 0
        ;;
    insert)
        [ -n "$QOS_WAN_IF" ] || exit 3
        [ -n "$RATE_DL" ] || exit 4
        [ -n "$RATE_UL" ] || exit 4
        IP=$2
        IFNAME=`get_public_iface $IP`
        if [ "$IFNAME" = "$QOS1_LAN_IF" ]; then
          N=`iptables -t mangle -nL $QOS1_LAN_CHAIN | grep -c $IP`
          # IP address already inserted
          if [ $N -ge 1 ]; then
            $0 delete $IP
          fi
          ID=${IP#$QOS1_LAN_NETWORK}
          ID=$((ID+1000))
          # Download
          iptables -t mangle -A $QOS1_LAN_CHAIN -d $IP -j MARK --set-mark $((QOS1_LAN_MARK+ID))
          tc class add dev $QOS1_LAN_IF classid 1:$ID parent 1:$QOS1_ID_ME htb rate ${RATE_DL}kbit ceil ${RATE_DL}kbit prio 4
          tc filter add dev $QOS1_LAN_IF protocol ip parent 1: handle $((QOS1_LAN_MARK+ID)) fw flowid 1:$ID
          # Upload
          tc class add dev $QOS_WAN_IF classid 1:$ID parent 1:$QOS1_ID_ME htb rate ${RATE_UL}kbit ceil ${RATE_UL}kbit prio 2
          tc filter add dev $QOS_WAN_IF protocol ip parent 1: handle $((QOS_WAN_MARK+ID)) fw flowid 1:$ID
          iptables -t mangle -A $QOS_WAN_CHAIN -s $IP -j MARK --set-mark $((QOS_WAN_MARK+ID))
        fi
        if [ "$IFNAME" = "$QOS2_LAN_IF" ]; then
          N=`iptables -t mangle -nL $QOS2_LAN_CHAIN | grep -c $IP`
          # IP address already inserted
          if [ $N -ge 1 ]; then
            $0 delete $IP
          fi
          ID=${IP#$QOS2_LAN_NETWORK}
          ID=$((ID+2000))
          # Download
          iptables -t mangle -A $QOS2_LAN_CHAIN -d  $IP -j MARK --set-mark $((QOS2_LAN_MARK+ID))
          tc class add dev $QOS2_LAN_IF classid 1:$ID parent 1:$QOS2_ID_ME htb rate ${RATE_DL}kbit ceil ${RATE_DL}kbit prio 4
          tc filter add dev $QOS2_LAN_IF protocol ip parent 1: handle $((QOS2_LAN_MARK+ID)) fw flowid 1:$ID
          # Upload
          tc class add dev $QOS_WAN_IF classid 1:$ID parent 1:$QOS2_ID_ME htb rate ${RATE_UL}kbit ceil ${RATE_UL}kbit prio 2
          tc filter add dev $QOS_WAN_IF protocol ip parent 1: handle $((QOS_WAN_MARK+ID)) fw flowid 1:$ID
          iptables -t mangle -A $QOS_WAN_CHAIN -s  $IP -j MARK --set-mark $((QOS_WAN_MARK+ID))
        fi
        if [ "$IFNAME" = "$QOS3_LAN_IF" ]; then
          N=`iptables -t mangle -nL $QOS3_LAN_CHAIN | grep -c $IP`
          # IP address already inserted
          if [ $N -ge 1 ]; then
            $0 delete $IP
          fi
          ID=${IP#$QOS3_LAN_NETWORK}
          ID=$((ID+3000))
          # Download
          iptables -t mangle -A $QOS3_LAN_CHAIN -d  $IP -j MARK --set-mark $((QOS3_LAN_MARK+ID))
          tc class add dev $QOS3_LAN_IF classid 1:$ID parent 1:$QOS3_ID_ME htb rate ${RATE_DL}kbit ceil ${RATE_DL}kbit prio 4
          tc filter add dev $QOS3_LAN_IF protocol ip parent 1: handle $((QOS3_LAN_MARK+ID)) fw flowid 1:$ID
          # Upload
          tc class add dev $QOS_WAN_IF classid 1:$ID parent 1:$QOS3_ID_ME htb rate ${RATE_UL}kbit ceil ${RATE_UL}kbit prio 2
          tc filter add dev $QOS_WAN_IF protocol ip parent 1: handle $((QOS_WAN_MARK+ID)) fw flowid 1:$ID
          iptables -t mangle -A $QOS_WAN_CHAIN -s  $IP -j MARK --set-mark $((QOS_WAN_MARK+ID))
        fi
        exit 0
        ;;
    delete)
        # Determine WAN interface
        [ -n "$QOS_WAN_IF" ] || exit 3
        [ -n "$RATE_DL" ] || exit 4
        [ -n "$RATE_UL" ] || exit 4
        IP=$2
        IFNAME=`get_public_iface $IP`
        if [ "$IFNAME" = "$QOS1_LAN_IF" ]; then
          ID=${IP#$QOS1_LAN_NETWORK}
          ID=$((ID+1000))
          # Remove from iptables
          iptables -t mangle -D $QOS1_LAN_CHAIN -d $IP -j MARK --set-mark $((QOS1_LAN_MARK+ID))/0xffffffff
          iptables -t mangle -D $QOS_WAN_CHAIN -s $IP -j MARK --set-mark $((QOS_WAN_MARK+ID))/0xffffffff
          # Remove classes and filters
          QOS_PREF_LIST=`tc filter show dev $QOS1_LAN_IF | awk '/handle/ { print $7 }'`
          for QOS_PREF in $QOS_PREF_LIST; do
             QOS_MARK_LIST=`tc filter show dev $QOS1_LAN_IF parent 1: protocol ip pref $QOS_PREF | awk '/handle/ { printf "%d\n", $6 }'`
             for QOS_MARK in $QOS_MARK_LIST; do
                if [ $QOS_MARK -eq $((QOS1_LAN_MARK+ID)) ]; then
                  tc filter del dev $QOS1_LAN_IF parent 1: protocol ip pref $QOS_PREF fw
                fi
             done
          done
          QOS_PREF_LIST=`tc filter show dev $QOS_WAN_IF | awk '/handle/ { print $7 }'`
          for QOS_PREF in $QOS_PREF_LIST; do
             QOS_MARK_LIST=`tc filter show dev $QOS_WAN_IF parent 1: protocol ip pref $QOS_PREF | awk '/handle/ { printf "%d\n", $6 }'`
            for QOS_MARK in $QOS_MARK_LIST; do
                if [ $QOS_MARK -eq $((QOS_WAN_MARK+ID)) ]; then
                  tc filter del dev $QOS_WAN_IF parent 1: protocol ip pref $QOS_PREF fw
                fi
             done
          done
          tc class del dev $QOS1_LAN_IF classid 1:$ID parent 1:$QOS1_ID_ME htb rate ${RATE_DL}kbit ceil ${RATE_DL}kbit prio 4
          tc class del dev $QOS_WAN_IF classid 1:$ID parent 1:$QOS1_ID_ME htb rate ${RATE_UL}kbit ceil ${RATE_UL}kbit prio 2
        fi
        if [ "$IFNAME" = "$QOS2_LAN_IF" ]; then
          ID=${IP#$QOS2_LAN_NETWORK}
          ID=$((ID+2000))
          # Remove from iptables
          iptables -t mangle -D $QOS2_LAN_CHAIN -d $IP -j MARK --set-mark $((QOS2_LAN_MARK+ID))/0xffffffff
          iptables -t mangle -D $QOS_WAN_CHAIN -s $IP -j MARK --set-mark $((QOS_WAN_MARK+ID))/0xffffffff
          # Remove classes and filters
          QOS_PREF_LIST=`tc filter show dev $QOS2_LAN_IF | awk '/handle/ { print $7 }'`
          for QOS_PREF in $QOS_PREF_LIST; do
             QOS_MARK_LIST=`tc filter show dev $QOS2_LAN_IF parent 1: protocol ip pref $QOS_PREF | awk '/handle/ { printf "%d\n", $6 }'`
             for QOS_MARK in $QOS_MARK_LIST; do
                if [ $QOS_MARK -eq $((QOS2_LAN_MARK+ID)) ]; then
                  tc filter del dev $QOS2_LAN_IF parent 1: protocol ip pref $QOS_PREF fw
                fi
             done
          done
          QOS_PREF_LIST=`tc filter show dev $QOS_WAN_IF | awk '/handle/ { print $7 }'`
          for QOS_PREF in $QOS_PREF_LIST; do
             QOS_MARK_LIST=`tc filter show dev $QOS_WAN_IF parent 1: protocol ip pref $QOS_PREF | awk '/handle/ { printf "%d\n", $6 }'`
            for QOS_MARK in $QOS_MARK_LIST; do
                if [ $QOS_MARK -eq $((QOS_WAN_MARK+ID)) ]; then
                  tc filter del dev $QOS_WAN_IF parent 1: protocol ip pref $QOS_PREF fw
                fi
             done
          done
          tc class del dev $QOS2_LAN_IF classid 1:$ID parent 1:$QOS2_ID_ME htb rate ${RATE_DL}kbit ceil ${RATE_DL}kbit prio 4
          tc class del dev $QOS_WAN_IF classid 1:$ID parent 1:$QOS2_ID_ME htb rate ${RATE_UL}kbit ceil ${RATE_UL}kbit prio 2
        fi
        if [ "$IFNAME" = "$QOS3_LAN_IF" ]; then
          ID=${IP#$QOS3_LAN_NETWORK}
          ID=$((ID+3000))
          # Remove from iptables
          iptables -t mangle -D $QOS3_LAN_CHAIN -d $IP -j MARK --set-mark $((QOS3_LAN_MARK+ID))/0xffffffff
          iptables -t mangle -D $QOS_WAN_CHAIN -s $IP -j MARK --set-mark $((QOS_WAN_MARK+ID))/0xffffffff
          # Remove classes and filters
          QOS_PREF_LIST=`tc filter show dev $QOS3_LAN_IF | awk '/handle/ { print $7 }'`
          for QOS_PREF in $QOS_PREF_LIST; do
             QOS_MARK_LIST=`tc filter show dev $QOS3_LAN_IF parent 1: protocol ip pref $QOS_PREF | awk '/handle/ { printf "%d\n", $6 }'`
             for QOS_MARK in $QOS_MARK_LIST; do
                if [ $QOS_MARK -eq $((QOS3_LAN_MARK+ID)) ]; then
                  tc filter del dev $QOS3_LAN_IF parent 1: protocol ip pref $QOS_PREF fw
                fi
             done
          done
          QOS_PREF_LIST=`tc filter show dev $QOS_WAN_IF | awk '/handle/ { print $7 }'`
          for QOS_PREF in $QOS_PREF_LIST; do
             QOS_MARK_LIST=`tc filter show dev $QOS_WAN_IF parent 1: protocol ip pref $QOS_PREF | awk '/handle/ { printf "%d\n", $6 }'`
            for QOS_MARK in $QOS_MARK_LIST; do
                if [ $QOS_MARK -eq $((QOS_WAN_MARK+ID)) ]; then
                  tc filter del dev $QOS_WAN_IF parent 1: protocol ip pref $QOS_PREF fw
                fi
             done
          done
          tc class del dev $QOS3_LAN_IF classid 1:$ID parent 1:$QOS3_ID_ME htb rate ${RATE_DL}kbit ceil ${RATE_DL}kbit prio 4
          tc class del dev $QOS_WAN_IF classid 1:$ID parent 1:$QOS3_ID_ME htb rate ${RATE_UL}kbit ceil ${RATE_UL}kbit prio 2
        fi
        exit 0;
        ;;
    stop)
        if [ -n "$QOS1_LAN_IF" ]; then
          # Download
          iptables -t mangle -D POSTROUTING -o $QOS1_LAN_IF -j $QOS1_LAN_CHAIN
          iptables -t mangle -F $QOS1_LAN_CHAIN
          iptables -t mangle -X $QOS1_LAN_CHAIN
          # Upload
          iptables -t mangle -D PREROUTING -i QOS1_LAN_IF -j $QOS_WAN_CHAIN
        fi
        if [ -n "$QOS2_LAN_IF" ]; then
          # Download
          iptables -t mangle -D POSTROUTING -o $QOS2_LAN_IF -j $QOS2_LAN_CHAIN
          iptables -t mangle -F $QOS2_LAN_CHAIN
          iptables -t mangle -X $QOS2_LAN_CHAIN
          # Upload
          iptables -t mangle -D PREROUTING -i QOS2_LAN_IF -j $QOS_WAN_CHAIN
        fi
        if [ -n "$QOS3_LAN_IF" ]; then
          # Download
          iptables -t mangle -D POSTROUTING -o $QOS3_LAN_IF -j $QOS3_LAN_CHAIN
          iptables -t mangle -F $QOS3_LAN_CHAIN
          iptables -t mangle -X $QOS3_LAN_CHAIN
          # Upload
          iptables -t mangle -D PREROUTING -i QOS3_LAN_IF -j $QOS_WAN_CHAIN
        fi
        if [ -n "$MOD_CP_QOS_WAN_CHAIN" ]; then
          iptables -t mangle  -F $MOD_CP_QOS_WAN_CHAIN
          iptables -t mangle  -X $MOD_CP_QOS_WAN_CHAIN
        fi
        # Remove qdisc from all interfaces
        QOS_IF_LIST=`tc qdisc show | awk '/qdisc htb / && $0 ~ QOS_ID_DF { print $5 }'`
        for QOS_IF in $QOS_IF_LIST; do
           tc qdisc del dev $QOS_IF root
        done
        exit 0
        ;;
    status)
        if [ -n "$PUBLIC_IF1_NAME" ]; then
          echo -n "QoS on LAN   : "
          tc qdisc show dev $QOS1_LAN_IF 2>/dev/null | grep -q htb
          if [ $? -eq 0 ]; then echo -n "running"; else echo -n "stopped"; fi
          echo " ($PUBLIC_IF1_NAME)"
        fi
        if [ -n "$PUBLIC_IF2_NAME" ]; then
          echo -n "QoS on LAN   : "
          tc qdisc show dev $QOS2_LAN_IF 2>/dev/null | grep -q htb
          if [ $? -eq 0 ]; then echo -n "running"; else echo -n "stopped"; fi
          echo " ($PUBLIC_IF2_NAME)"
        fi
        if [ -n "$PUBLIC_IF3_NAME" ]; then
          echo -n "QoS on LAN   : "
          tc qdisc show dev $QOS3_LAN_IF 2>/dev/null | grep -q htb
          if [ $? -eq 0 ]; then echo -n "running"; else echo -n "stopped"; fi
          echo " ($PUBLIC_IF3_NAME)"
        fi
        echo -n "QoS on WAN   : "
        tc qdisc show dev $QOS_WAN_IF 2>/dev/null | grep -q htb
        if [ $? -eq 0 ]; then echo -n "running"; else echo -n "stopped"; fi
        echo " ($QOS_WAN_IF)"
        exit 0
        ;;
    cronstart)
        if [ "$MOD_CP_QOS_RATE_ENABLED" != "1" ] && [ "$MOD_CP_QOS_UPDOWN_SPEED_ENABLED" != "1" ]; then
          exit 0
        fi
        [ -n "$QOS_WAN_IF" ] || exit 3
        tc qdisc show dev $QOS_WAN_IF 2>/dev/null | grep -q htb && exit 1
        $0 start
        ;;
    *)
        echo "Usage: $0 {start|stop|status|restart|cronstart}"
        exit 1
        ;;
esac
