#!/bin/sh

[ -z "$ROOT" ] && ROOT=/www
CONFIG=$ROOT/config
SCRIPT=$ROOT/script

source $CONFIG/ap.conf
source $CONFIG/ng.conf

source $SCRIPT/utils/network.sh
source $SCRIPT/utils/wifi.sh

wanSpeed=`getWanSpeed`

isQosEnabledOnSsid() {
  local ssid="$1"

  eval local enabled="\$SSID${ssid}_ENABLED"
  eval local qosEnabled="\$SSID${ssid}_QOS"
  [ "$enabled" == 1 -a "$qosEnabled" == 1 ] && echo 1
}

isQosActivatedOnInf() {
  local inf="$1"
  qdisc=`tc qdisc show dev $inf 2>/dev/null | grep "qdisc hfsc"`
  [ ! -z "$qdisc" ] && echo 1
}
isQosActivatedOnSsid() {
  local ssid="$1"
  local infs=`getSsidWirelessInf $ssid`
  for inf in $infs ; do
    [ `isQosActivatedOnInf $inf` ] || return
  done
  echo 1
}

# enable & disable
disableQosOnInf() {
  local inf="$1"
  tc qdisc    del dev $inf  root &>/dev/null
  tc qdisc    del dev $inf  ingress &>/dev/null
}
disableQosOnSsid() {
  local ssid="$1"
  local infs=`getSsidWirelessInf $ssid`
  for inf in $infs ; do
    disableQosOnInf $inf
  done
}

enableQosOnInf() {
  local inf="$1"
  disableQosOnInf $1

  [ $wanSpeed -gt 100 ] && fullSpeed=`getWifiSpeed $inf` || fullSpeed=$wanSpeed
  local bulkSpeed=$((fullSpeed * 80 / 100))
  local prioSpeed=$((fullSpeed * 20 / 100))

  tc qdisc    add dev $inf  root        handle 1     hfsc default 11
  tc class    add dev $inf  parent 1:   classid 1:1  hfsc sc rate ${fullSpeed}Mbit  ul rate ${fullSpeed}Mbit
  tc class    add dev $inf  parent 1:1  classid 1:10 hfsc sc umax 1540 dmax 5ms rate ${prioSpeed}Mbit  ul rate ${fullSpeed}Mbit
  tc class    add dev $inf  parent 1:1  classid 1:11 hfsc sc umax 1540 dmax 5ms rate ${bulkSpeed}Mbit  ul rate ${bulkSpeed}Mbit
  tc class    add dev $inf  parent 1:1  classid 1:20 hfsc ls rate 48bit             ul rate 96bit

  tc qdisc  add   dev $inf  parent 1:10 handle 10: fq_codel
  tc qdisc  add   dev $inf  parent 1:11 handle 11: fq_codel

  # cna detect traffic
  tc filter   add dev $inf  parent 1:0    protocol ip prio 1 handle 20 fw flowid 1:20

  # prioritize ssh
  tc filter   add dev $inf  parent 1:0    protocol ip prio 2 u32 match ip sport 22 0xffff flowid 1:10
  tc filter   add dev $inf  parent 1:0    protocol ip prio 2 u32 match ip dport 22 0xffff flowid 1:10
  # prioritize icmp
  tc filter   add dev $inf  parent 1:0    protocol ip prio 2 u32 match ip protocol 1 0xff flowid 1:10
  # prioritize marked
  tc filter   add dev $inf  parent 1:0    protocol ip prio 3 handle 10 fw flowid 1:10
}
enableQosOnSsid() {
  local ssid="$1"
  local infs=`getSsidWirelessInf $ssid`
  for inf in $infs ; do
    enableQosOnInf $inf
  done
}

# enable ip & disable ip
getQosIndexOfIp() {
  local ip="$1"
  local ip3=`echo "$ip" | awk -F'.' '{print $3}'`
  local ip4=`echo "$ip" | awk -F'.' '{print $4}'`
  local index=$((ip3 * 256 + ip4 + 10))
  printf '%x' $index
}

disableQosOfIpOnInf() {
  local inf="$1"
  [ `isQosActivatedOnInf "$inf"` ] || return

  local ip="$2"
  local index=`getQosIndexOfIp "$ip"`

  pref=`tc filter show dev $inf | grep flowid | grep "1:$index" | awk '{print $7}'`
  [ ! -z "$pref" ] && tc filter del   dev $inf  pref "$pref" &>/dev/null
  tc qdisc  del   dev $inf  parent 1:"$index" &>/dev/null
  tc class  del   dev $inf  classid 1:"$index" &>/dev/null
}
disableQosOfIpOnSsid() {
  local ssid="$1"
  local infs=`getSsidWirelessInf $ssid`
  for inf in $infs ; do
    disableQosOfIpOnInf $inf "$2"
  done
  disableQosOfIpOnInf "`getSsidInf $ssid`" "$2"
}

enableQosOfIpOnInf() {
  local inf="$1"
  [ ! `isQosActivatedOnInf "$inf"`  ] && enableQosOnInf $inf

  local ip="$2"
  local speed="$3"
  [ -z "$speed" -o "$speed" == 0 ] && return
  local dir="$4"
  [ -z "$dir" ] && dir=dst

  disableQosOfIpOnInf "$inf" "$ip"

  local unit="Mbit"
  [ "$speed" -gt 100 ] && unit="Kbit"
  [ "$speed" -gt 100000 ] && unit="bit"
  local index=`getQosIndexOfIp "$ip"`

  tc class  add   dev $inf  parent 1:10 classid 1:"$index" hfsc ls rate "${speed}${unit}" ul rate "${speed}${unit}"
  tc filter add   dev $inf  parent 1: prio 10 protocol all u32 match ip $dir "$ip"/32 flowid 1:"$index"
}
enableQosOfIpOnSsid() {
  local ssid="$1"
  local infs=`getSsidWirelessInf $ssid`
  for inf in $infs ; do
    enableQosOfIpOnInf $inf "$2" "$3"
  done
}