#!/bin/bash
# Copyright (C) 2000-2017 Synology Inc. All rights reserved.

set -eux

script_root=`dirname $0`
package_root=`realpath -m ${script_root}/..`
driver_name=`basename ${package_root}`
driver_root="${SYNOPKG_PKGDEST:-${package_root}/target}/${driver_name}"
log_root="${package_root}/var/log"

apply_if_config()
{
  target_interface_name=$1
  if [[ ! -v BOOTPROTO ]] || [ "$BOOTPROTO" = "dhcp" ]
  then
    synonet --dhcp $target_interface_name || true
  else
    # workaround: From build 42962 and later, IP settings must be explicitly configured.
    source /etc/VERSION
    if [ $buildnumber -ge 42962 ] && [[ -v IPADDR && -v NETMASK ]]
    then
      ifconfig $target_interface_name inet ${IPADDR} netmask ${NETMASK}
      netstat -nr

      if ! ip route | grep -E ^default
      then
        default_gateway_interface=`get_key_value /etc/iproute2/config/default-gateway DEVICE` || true
        # The value of `default-gateway ` may be empty when default gateway was set to a removable device.
        if [ "${default_gateway_interface}" = "${target_interface_name}" ] || [ -z "${default_gateway_interface}" ]
        then
          gateway=`get_section_key_value /etc/iproute2/config/gateway_database ${target_interface_name} gateway`
          if [ -n "${gateway}" ]
          then
            route add default gw ${gateway}
            netstat -nr
            if [ -z "${default_gateway_interface}" ]
            then
              echo "DEVICE=${target_interface_name}" > /etc/iproute2/config/default-gateway
            fi
          fi
        fi
      fi
    fi
  fi
}

is_ovs_enable()
{
    if [ ! -f  '/usr/syno/etc/synoovs/ovs_reg.conf' ]; then
        return 1
    fi

    use=`cat /usr/syno/etc/synoovs/ovs_reg.conf | wc -l`
    if [ 0 -eq $use ]; then
        return 1
    else
        return 0
    fi
}

set_ovs_interface()
{
  interface_name=$1
  action=$2

  config_file_ovs=/etc/sysconfig/network-scripts/ifcfg-ovs_$interface_name
  config_storage_location_ovs=$package_root/etc/ifcfg-ovs_$interface_name

  if is_ovs_enable
  then
    if [ -f "$config_file_ovs" ] && [ "$action" = "down" ]
    then
      cp $config_file_ovs $config_storage_location_ovs
    elif [ "$action" = "up" ] && [ -f "$config_storage_location_ovs" ]
    then
      cp $config_storage_location_ovs $config_file_ovs
    fi
    if [ "$action" = "up" ]
    then
      if ! ovs-vsctl show | grep "Interface \"$interface_name\""
      then
        ovs-vsctl add-br ovs_$interface_name
        ovs-vsctl add-port ovs_$interface_name $interface_name
        ifconfig ovs_$interface_name $action
      fi
    fi

    if ifconfig ovs_$interface_name 2> /dev/null
    then
      if [ "$action" = "down" ]
      then
        ifconfig ovs_$interface_name $action
        ovs-vsctl del-br ovs_$interface_name
      fi

      if [ "$action" = "up" ]
      then
        if [ -r "$config_file_ovs" ]
        then
          source $config_file_ovs
        fi
        apply_if_config ovs_$interface_name
      fi
    fi
  fi
}

set_interfaces()
{
  action=$1
  target_interface_name=${2:-}
  all_interface_names=$(ls /sys/class/net)

  if [ -n ${target_interface_name} ] && [ ! -e "/sys/class/net/${target_interface_name}" ] && [ "$action" = "down" ]
  then
    echo "${target_interface_name} is already detached."
    set_ovs_interface ${target_interface_name} down
    return 0
  fi

  for interface_name in ${all_interface_names}
  do
    # Skip other interfaces if an interface was explicitly specified 
    if [[ -n "$target_interface_name" && "$interface_name" != "$target_interface_name" ]]
    then
      continue
    fi

    # Skip loopback/docker interface, since it doesn have a device/driver
    # folder.
    if [ ! -e /sys/class/net/$interface_name/device/driver ]
    then
      continue
    fi

    # For all other interfaces list the device driver folder and
    # bring interface up/down if the device driver folder links to
    # something with the target device driver in its name.
    driver_location=$(ls -ld /sys/class/net/$interface_name/device/driver)
    if [ ! -z "$(echo "$driver_location" | grep $driver_name)" ]
    then
      config_file=/etc/sysconfig/network-scripts/ifcfg-$interface_name
      config_storage_location=$package_root/etc/ifcfg-$interface_name
      if [ -f "$config_file" ] && [ "$action" = "down" ]
      then
        cp $config_file $config_storage_location
      elif [ "$action" = "up" ] && [ -f "$config_storage_location" ]
      then
        cp $config_storage_location $config_file
      fi
      ifconfig $interface_name $action
      set_ovs_interface $interface_name $action
      if [ "$action" = "up" ] && ! is_ovs_enable
      then
        if [ -r "$config_file" ]
        then
          source $config_file
        fi
        apply_if_config $interface_name
      fi

      if [ "$action" = "up" ] && [ -e ${script_root}/apply-private-flags ]
      then
        sh ${script_root}/apply-private-flags $interface_name
      fi
    fi
  done
}

count_usb_interfaces()
{
  ls -l /sys/class/net/ | grep /usb | wc -l
}

mkdir -p "${log_root}"
exec &> >(tee -a "${log_root}/start-stop-status.log")
echo "----------"
date
grep -E '^(version|create_time)' ${package_root}/INFO
echo $*

case $1 in
  start)
    if [ -e ${script_root}/apply-memory-setting ]
    then
      sh ${script_root}/apply-memory-setting
    fi

    if [ -w /sys/module/usbcore/parameters/autosuspend ]
    then
      echo -1 > /sys/module/usbcore/parameters/autosuspend
    fi

    initial_count=`count_usb_interfaces`

    if [ -e ${driver_root}/mii.ko ]
    then
      /sbin/insmod ${driver_root}/mii.ko
    fi
    if [ -e ${driver_root}/usbnet.ko ]
    then
      /sbin/insmod ${driver_root}/usbnet.ko
    fi
    /sbin/insmod ${driver_root}/${driver_name}.ko

    if [ -r /usr/lib/udev/rules.d/51-usb-${driver_name}-net.rules ]
    then
      exit 0
    fi

    for i in `seq 1 60`
    do
      if [ `count_usb_interfaces` -ne $initial_count ]
      then
        break
      fi
      sleep 1
    done

    set_interfaces up
    exit 0
  ;;
  stop)
    set_interfaces down
    /sbin/rmmod ${driver_root}/${driver_name}.ko || true
    if [ -e ${driver_root}/usbnet.ko ]
    then 
      /sbin/rmmod ${driver_root}/usbnet.ko || true
    fi
    if [ -e ${driver_root}/mii.ko ]
    then
      /sbin/rmmod ${driver_root}/mii.ko    || true
    fi
    exit 0
  ;;
  status)
    /sbin/lsmod | grep ${driver_name} && exit 0 || exit 3
  ;;
  killall)
    exit 0
  ;;
  log)
    exit 0
  ;;
  reload)
    set_interfaces down $2
    set_interfaces up $2
    exit 0
  ;;
  remove)
    set_interfaces down $2
    exit 0
  ;;
esac
