#!/bin/sh

# This module does etcnet configuration for L2TP interfaces
# for openl2tp software.

# Turn of auto expansion
set -f

# set `verbose' variable to get debug output for `alterator -l -d'
verbose=

. shell-error

v() {
  verbose "__DEBUG__" $@
}

readonly PREFIX="/etc/net"
readonly ETCNET_IFACE_TYPE="l2tp"
readonly WAIT_TIME=3
readonly IFACE_UP_HELPER='/usr/lib/alterator-net-l2tp/ifup-pre'

alterator_api_version=1

. alterator-sh-functions
. alterator-net-functions
. alterator-hw-functions


status_iface()
{
  v "status_iface() -- enter"

  if [ -z "$1" ]; then
      v "status_iface() -- bad invocation"
    return
  fi

  local iface="$1"
  local iface_dir="${PREFIX}/ifaces/$1"

  if ! [ -d "$iface_dir" ]; then
      v "status_iface() -- bad iface $iface_dir"
    return
  fi

  local info=

  v "status_iface() -- iface dir: $iface_dir"

  local ip_local="$(_ "N/A")"
  local ip_remote="$(_ "N/A")"

  local connection_state=

  # check connection aliveness
  if netdev_is_up "$iface"; then
    v "status_iface() -- $iface_dir is up"
    info="`_ "connection is established"`"
    connection_state="is_up"
    # read_iface_current_addr is at /usr/bin/alterator-net-functions
    ip_local="$(read_iface_current_addr "$iface")"
    local r=".*[[:space:]]+peer[[:space:]]+([.0-9/]+).*"
    ip_remote="$(/sbin/ip -4 a s "$iface" 2>/dev/null|sed -r -n "s,$r,\1,p" | head -n1)"
    v "status_iface() -- IP local = $ip_local, IP remote = $ip_remote"
    ip_local="${ip_local:-N/A}"
    ip_remote="${ip_remote:-N/A}"
  else
    v "status_iface() -- $iface_dir is down"
    connection_state="is_down"
    info="`_ "connection is down"`"
  fi

  # l2tpsession file
  local username=
  local password=
  if [ -f "$iface_dir/l2tpsession" ]; then
    username="$(cat "$iface_dir/l2tpsession" | sed -n -e 's/^.*user_name=\([^[:space:]]\+\).*$/\1/p')"
    password="$(cat "$iface_dir/l2tpsession" | sed -n -e 's/^.*user_password=\([^[:space:]]\+\).*$/\1/p')"
  fi

  # l2tptunnel file
  local server=
  if [ -f "$iface_dir/l2tptunnel" ]; then
    server="$(cat "$iface_dir/l2tptunnel" | sed -n -e 's/^.*dest_ipaddr=\([^[:space:]]\+\).*$/\1/p')"
  fi

  # l2tpppp file
  local default_route=
  if [ -f "$iface_dir/l2tpppp" ]; then
    default_route="$(cat "$iface_dir/l2tpppp" | sed -n -e 's/^.*default_route=\([^[:space:]]\+\).*$/\1/p')"
  fi
  if [ -z "$default_route" ]; then
      default_route="no"
  fi
  v "status_iface() -- default_route: $default_route"

  # options file
  local host="$(read_iface_option "$iface_dir" "HOST")"
  local start_at_boot="$(read_iface_option "$iface_dir" "ONBOOT")"
  if [ -z "$start_at_boot" ]; then
      start_at_boot="yes"
  fi
  v "status_iface() -- start_at_boot: $start_at_boot"

  write_string_param "label_status" "$info"
  write_string_param "label_status_remote_ip" "$ip_remote"
  write_string_param "label_status_local_ip" "$ip_local"
  write_string_param "input_server" "$server"
  write_string_param "input_username" "$username"
  write_string_param "input_password" "$password"
  write_string_param "list_possible_hosts" "$host"
  write_bool_param "bool_default_route" "$default_route"
  write_bool_param "bool_auto_start" "$start_at_boot"
  write_string_param "connection_state" "$connection_state"
}


# https://bugzilla.altlinux.org/26124
# stanv@: я переписывал модуль с pptp. Нужно проверить это для l2tp ?
write_clamp_mss()
{
    RULE="-p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu"
    RULEDIR="$name/fw/iptables/mangle/"
    RULEFILE="$RULEDIR/FORWARD"
    if [ -s "$RULEFILE" ]; then
        if ! grep -q "^$RULE$" "$RULEFILE"; then
            echo "$RULE" >> "$RULEFILE"
        fi
    else
        mkdir -p "$RULEDIR"
        echo "$RULE" > "$RULEFILE"
    fi
}


connection_save()
{
  v "connection_save() -- enter"

  local iface="$in_list_interfaces"

  if [ -z "$iface" ]; then
    v "connection_save() -- wrong invocation"
    return
  fi

  v "connection_save() -- save $iface"

  local iface_dir="${PREFIX}/ifaces/${iface}"


  # ONBOOT OPTION
  if [ "$in_bool_auto_start" = "#t" ]; then
    write_iface_option "$iface_dir" "ONBOOT" "yes"
  fi

  if [ "$in_bool_auto_start" = "#f" ]; then
    write_iface_option "$iface_dir" "ONBOOT" "no"
  fi

  # HOST OPTION
  if [ -n "$in_list_possible_hosts" ]; then
    if [ "$in_list_possible_hosts" = "do_not_use" ]; then
      v "connection_save() -- remove HOST interface option"
      shell_config_del "${iface_dir}/options" "HOST"
    else
      v "connection_save() -- set HOST interface option to $in_list_possible_hosts"
      write_iface_option "$iface_dir" "HOST" "$in_list_possible_hosts"
    fi
  fi

  # L2TPSESSION FILE
  if [ -n "$in_input_username" -a -n "$in_input_password" ]; then
    v "connection_save() -- write l2tpsession file"
    echo "user_name=${in_input_username} user_password=${in_input_password}" > "$iface_dir/l2tpsession"
  else
    if [ -f "$iface_dir/l2tpsession" ]; then
      v "connection_save() -- remove l2tpsession"
      rm -f "$iface_dir/l2tpsession"
    fi
  fi

  # L2TPTUNNEL FILE
  if [ -n "$in_input_server" ]; then
    v "connection_save() -- write l2tptunnel file"
    echo "dest_ipaddr=${in_input_server}" > "$iface_dir/l2tptunnel"
  else
    if [ -f "$iface_dir/l2tptunnel" ]; then
      v "connection_save() -- remove l2tptunnel"
      rm -f "$iface_dir/l2tptunnel"
    fi
  fi

  # L2TPPPP FILE
  local bool=
  if [ "$in_bool_default_route" = "#t" ]; then
    bool="yes"
  else
    bool="no"
  fi
  v "connection_save() -- write l2tpppp file"
  echo "default_route=${bool}" > "$iface_dir/l2tpppp"

  # SUPPLY IFACE UP HELPER
  if [ ! -e "$iface_dir/ifup-pre" -a -e "$IFACE_UP_HELPER" ]; then
      v "connection_save() -- add $IFACE_UP_HELPER"
      cp "$IFACE_UP_HELPER" "$iface_dir"
      chmod 755 "$iface_dir"
  fi

  return
}


# CREATE NEW CONNECTION
connection_new()
{
  v "connection_new() -- enter"

  local iface="$in_input_new_iface_name"

  if [ -z "$iface" ]; then
    return
  fi

  local iface_dir="${PREFIX}/ifaces/$iface"

  if [ -d "$iface_dir" ]; then
    v "connection_new() -- configuration dir $iface_dir already exists"
    write_error "`_ "Network interface $iface already exists"`"
    return
  fi

  v "connection_new() -- create configuration dir $iface_dir"
  mkdir -p -- "$iface_dir"

  write_iface_option "$iface_dir" "TYPE" "$ETCNET_IFACE_TYPE"
}


# DELETE CONNECTION
connection_remove()
{
  v "connection_remove() -- enter"

  local iface="$in_iface"
  if [ -z "$iface" ]; then
    v "connection_remove() -- wrong invocation"
    return
  fi

  local iface_dir="${PREFIX}/ifaces/$iface"
  if ! [ -d "$iface_dir" ]; then
    v "connection_remove() -- no configuration dir $iface_dir"
    return
  fi

  if netdev_is_up "$iface"; then
      v "connection_remove() -- bring down interface $iface"
    iface_down "$iface"
  fi

  v "connection_remove() -- remove configuration dir $iface_dir"
  rm -rf -- "$iface_dir"
}


# LIST POSSIBLE HOSTS INTERFACES
list_possible_hosts() {
  v "list_possible_hosts() -- enter"

  write_enum_item "do_not_use" "`_ "Use any appropriate interface"`"

  # list_eth|write_enum
  all_ifaces="$(list_iface)"

  for iface in $all_ifaces; do
    iface_hw="$(netdev_read_mac "$iface")"
    iface_inet="$(read_iface_current_addr "$iface")"
    iface_desc="$iface"
    [ -n "$iface_hw" ] && iface_desc="$iface_desc - $iface_hw"
    [ -n "$iface_inet" ] && iface_desc="$iface_desc ($iface_inet)"

    write_enum_item "$iface" "$iface_desc"
  done
}


# LIST ALL L2TP INTERFACES
list_interfaces() {
  v "list_interfaces() -- enter"
  local iface=

  for i in $(find "$etcnet_iface_dir" -mindepth "1" -maxdepth "1" -type "d"); do
    if [ "$(read_iface_option "$i" TYPE)" == "$ETCNET_IFACE_TYPE" ]; then
      iface="${i##*/}"
      v "list_interfaces() -- list $iface as L2TP interface"
      write_enum_item "$iface" "$iface"
    fi
  done
}


# INTERFACE UP
connection_up()
{
  v "connection_up() -- enter"

  if [ -z "$in_iface" ]; then
    v "connection_up() -- incorrect invocation"
  fi

  v "connection_up() -- down interface $in_iface"
  iface_up "$in_iface" "$WAIT_TIME"
}


# INTERFACE DOWN
connection_down()
{
  v "connection_down() -- enter"

  if [ -z "$in_iface" ]; then
    v "connection_down() -- incorrect invocation"
  fi

  v "connection_down() -- down interface $in_iface"
  iface_down "$in_iface" "$WAIT_TIME"
}


# MAIN LOOP
on_message() {
  case "$in_action" in
    type)
      write_type_item "input_new_iface_name" "hostname"
      write_type_item "input_server" "hostname"

      ;;

    list)

      case "$in__objects" in

        list_possible_hosts)
          # ALL NETWORK INTERFACES THAT CAN BE A HOST FOR L2TP CONNECTION
          v "on list message: list list_possible_hosts"
          list_possible_hosts

          ;;

        list_interfaces)
          # ALL L2TP INTERFACES
          v "on list message: list list_interfaces"
          list_interfaces

          ;;

        *)
          # UNDEFINED LIST REQUEST
          v "on list message: undefined list request: $in__objects" 1>&2

          ;;

      esac
      ;;

    read)

      case "$in__objects" in

        status)
          # READ INTERFACE STATUS
          v "on read message: read interface status"
          status_iface "$in_iface"

          ;;

        *)
          # UNDEFINED READ REQUEST
          v "on read message: undefined read request: $in__objects" 1>&2

          ;;

      esac

      ;;

    write)

      case "$in__objects" in

        connection_new)
          # CREATE NEW CONNECTION
          v "on write: create new connection"
          connection_new

          ;;

        connection_remove)
          # REMOVE CONNECTION
          v "on write: delete connection"
          connection_remove

          ;;

        connection_save)
          # SAVE CONNECTION
          connection_save

          ;;

        *)
          # UNDEFINED READ REQUEST
          v "on write: undefined read request: $in__objects" 1>&2

          ;;

      esac
      ;;

  esac
}

alterator_export_proc connection_up
alterator_export_proc connection_down

message_loop

# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=sh
