#! /bin/bash

function usage() {
  <<EoF cat
Make this host an IPv6 gateway, by 
 -- setting up the IPv6 addresses and routes, and
 -- writing a suitable radvd.conf file.

Call with IFACE= the device facing the subnet that
will be served.

Typically should be called as soon as 
 a) the subnet interface is up, and
 b) this host's connectivity to the internet is up.

Typical usage:
  $0 [options]

Options include:
  -h		print this message
  -v		verbose
  -n		no-op i.e. dry run
EoF
}

#################################
## All the stuff that needs to be done on a per-subnet_dev basis.

function conf_stanza() {

  subnet_dev="$1"

  # Map a device name to a small integer.
  # We use this as the subnet number (aka the SLA ID number).
  subnet=$( get_devnum $subnet_dev )

  if test "_$odev" = "_6to4" ; then
    firstlevelsubnet=OK
  else
    firstlevelsubnet=""
    1>&2 echo "Cannot (yet?) handle sub-sub-nets."
  fi

  printf -v hexip4 '%02x%02x:%02x%02x' $(echo $WANip4 | sed 's/[.]/ /g')
  prefix=2002:$hexip4:$subnet

  subnet_ip6="$prefix:$(get_eui $subnet_dev )"

  if test -n "$mode_v" ; then
    if test -n "$didsome" ; then
      echo ""
    fi
    echo "odev:        $odev"
    echo "WANip4:      $WANip4"
    echo "prefix:      $prefix"
    printf "subnet_ip6:  %-40s %s\n" "$subnet_ip6"   "${firstlevelsubnet:-not OK}"
    printf "subnet_dev:  %-40s %s\n" "$subnet_dev"   "${firstlevelsubnet:-not OK}"
    didsome=yes
  fi

  if test -n "$mode_n" ; then
    return
  fi

  if test -z "$firstlevelsubnet" ; then
    return
  fi

  # put the appropriate address on the device serving the subnet LAN:
  2>/dev/null ifconfig $subnet_dev del $subnet_ip6/64 || true
  ifconfig $subnet_dev add $subnet_ip6/64

  # And install the route:
  ip -6 route ls dev $subnet_dev | while read route junk ; do
    if test "_${route#2002:}" != "_${route}" ; then
      ip -6 route del $route dev $subnet_dev
    fi
  done
  ip route add $prefix::/64 dev $subnet_dev

<<EoF cat >> /var/state/radvd.conf
# Advertise on the subnet-side interface:

interface $subnet_dev {
	AdvSendAdvert on;

# This may be needed on some interfaces which are not active when
# radvd starts, but become available later on; see man page for details.

	# IgnoreIfMissing on;

# These settings cause advertisements to be sent every 3-10 seconds.  This
# range is good for 6to4 with a dynamic IPv4 address, but can be greatly
# increased when not using 6to4 prefixes.

	MinRtrAdvInterval 3;
	MaxRtrAdvInterval 10;


# Disable Mobile IPv6 support

	AdvHomeAgentFlag off;

# Workaround some strange bug:
	AdvCurHopLimit 0;

# This prefix describes the local, subnet piece of 6to4 tunnel.
# This prefix is what vassals should use to autoconfigure themselves.
	prefix $prefix::/64
	{
		AdvOnLink on;
		AdvAutonomous on;
		AdvRouterAddr off;
		AdvPreferredLifetime 600;  # ten minutes
		AdvValidLifetime    1800;  # thirty minutes
	};


};

EoF

}

########################
## main program
########################

while test -n "$*" ; do
  opt=$1 ; shift
  case $opt in
    -n)
      mode_n=yes
      ;;
    -v)
      mode_v=yes
      ;;
    -h)
      usage
      exit 0
      ;;
    *)
      1>&2 echo "Extraneous verbiage '$opt'"
      exit 1
  esac
done

bindir=$( dirname $0 )
if test -z "$have_ip_conf_utils" ; then
  . $bindir/ip-conf-utils
fi

< <( get_our_ipaddrs ) MapFile ip6addr WANip4 odev

install -d /var/state		## rarely (if ever) necessary

<<EoF cat > /var/state/radvd.conf

######  radvd configuration file
######  Do not edit!
######  Automatically constructed by $0

EoF

# Note that if a device is no "UP" it will not be
# listed by ifc-prop and will be left out of the
# radvd.conf file.
# This is undesirable but consistent with the fact
# that the radvd daemon would exit if it saw an 
# unusable device in the .conf file
# For now that means this configuration script should
# be re-run every time a device goes up or down.
# (In the longer run it would be nice to configure
# all the devices and persuade radvd to tolerate
# devices that are not UP at the moment.)
for subnet_dev in $(/etc/default/ifc-prop -p private) ; do
   conf_stanza $subnet_dev
done


if test -z "$mode_n" ; then
# If the advertising daemon is running, signal it to restart.
# If not running and $start_radvd, try to start it.
# Otherwise do nothing.
  pid=$( running_pid /var/run/radvd.pid )
  if test -z "$pid" ; then
    # not running
    if test -n "$start_radvd" ; then
      1>&2 echo "About to start radvd"
      radvd
    fi
  else
    if test -n "$pid" ; then
      if kill -1 $pid ; then
	1>&2 echo "Signalled to restart radvd, namely pid $pid"
      fi
    fi
  fi
  if ! test -r /etc/radvd.conf ; then
    1>&2 echo "It seems /etc/radvd.conf does not exist; consider:"
    1>&2 echo "  :; ln -s /var/state/radvd.conf /etc/"
  fi
  fwd=$( 2>/dev/null cat /proc/sys/net/ipv6/conf/all/forwarding)
  if test "_$fwd" != "_1" ; then
    1>&2 echo "It seems ipv6 fowarding is not enabled;  consider:"  
    1>&2 echo "   echo 1 > /proc/sys/net/ipv6/conf/all/forwarding"
  fi
  if test -z $( running_pid /var/run/radvd.pid ) ; then
    1>&2 echo "It seems radvd is not running;  consider:"
    1>&2 echo "  :; radvd"
  fi
fi
