#!/bin/sh
# Filename:      grml-btnets
# Purpose:       Program to do something
# Authors:       grml-team (grml.org), (c) Michael Gebetsroither <gebi@grml.org>
# Bug-Reports:   see http://grml.org/bugs/
# License:       This file is licensed under the GPL v2.
################################################################################


###
### __INCLUDES
###
. /etc/grml/sh-lib
#. /etc/grml/sysexits-sh



###
### __VARIABLES
###

verbose_=0
TEMPLATE_CONFIG_DIR_='/usr/share/grml-btnet/templates'
DHCPD_TEMPLATE_FILE_='/usr/share/grml-btnet/templates/dhcpd_config'
DHCPD_CONFIG_FILE_='/var/lib/grml-btnet/dhcpd.conf'
BTPIN_=""       # pin for bluetooth
PIN_FILE_='/etc/bluetooth/pin'  # pin for bluetooth server services
DEV_UP_DIR_='/etc/bluetooth/pan'
DEV_UP_SCRIPT_="$DEV_UP_DIR_/dev-up"    # will be executed if an interface comes up
BR_IFACE_='grmlbtnet'            # default bridge interface
ENABLE_IPFORW_='false'      # should ip-forward be enabled (default eth0)
FORWARD_IFACE_='eth0'       # gate to the internet

NETWORK_="192.168.10.0"     # the network
SERVER_IP_=""   # the ip of the computer running grml-btnets (the first ip in the subnet)
                # typically 192.168.10.1
NETMASK_="255.255.255.0"    # the netmask, currently fixed at /24
IPRANGE_FROM_=''            # host-min
IPRANGE_TO_=''              # host-max
NAMESERVERS_=''             # the nameserver(s)


###
### __FUNCTIONS
###

function printUsage
{
    cat <<EOT
Usage: "$PROG_NAME__" [OPTIONS] <command>

$PROG_NAME__ is the server config program for ip over bluetooth

COMMANDS:
   help             This help text
   start            Start service
   stop             Stop service
   <default>        start

OPTIONS:
   -s [subnet]  An empty subnet with netmask 255.255.255.0 (default=192.168.10.0/24)
   -i [iface]   Enable ip-forwarding for this interface (default=eth0)
   -p <pin>     The bluetooth pin
   -v           verbose (show what is going on, v++)
   -h           this help text

EOT
}


function calcNetworkParams
{
    IPRANGE_FROM_=`execute "ipcalc -nb $NETWORK_/$NETMASK_" warn |awk '/HostMin/{print $2}'`
    IPRANGE_TO_=`execute "ipcalc -nb $NETWORK_/$NETMASK_" warn |awk '/HostMax/{print $2}'`
    NETWORK_=`execute "ipcalc -nb $NETWORK_/$NETMASK_" warn |awk '/Network:/{print $2}'`
    NETWORK_=${NETWORK_%/*}
    SERVER_IP_="$IPRANGE_FROM_"

    NAMESERVERS_="`netGetNameservers warn |tr ' ' ','`"
    NAMESERVERS_="${NAMESERVERS_:-SERVER_IP_}"

    notice "IPRANGE_FROM_ = $IPRANGE_FROM_"
    notice "IPRANGE_TO_ = $IPRANGE_TO_"
    notice "NETWORK_ = $NETWORK_"
    notice "SERVER_IP_ = $SERVER_IP_"
    notice "NAMESERVERS_ = $NAMESERVERS_"
}


function createDevUpScript
{
    mkdir -p $DEV_UP_DIR_
    cat > $DEV_UP_SCRIPT_ <<EOT
#!/bin/sh
# \$1 is the upcoming interface
# \$2 is the bdaddr of the connecting client

brctl addif $BR_IFACE_ \$1
ifconfig \$1 0.0.0.0
EOT
    chmod 755 $DEV_UP_SCRIPT_
}

function removeDevUpScript
{
    rm -f $DEV_UP_SCRIPT_
}


function setPin
{
    echo "$1" > "$PIN_FILE_"
}
function unsetPin
{
    echo -n "" > "$PIN_FILE_"
}


function startIpForw
{
    echo 1 > /proc/sys/net/ipv4/ip_forward
    iptables -t nat -A POSTROUTING -o $FORWARD_IFACE_ -j MASQUERADE
}

function stopIpForw
{
    echo 0 > /proc/sys/net/ipv4/ip_forward
    iptables -t nat -D POSTROUTING -o $FORWARD_IFACE_ -j MASQUERADE
}


function startDhcpd
{
    execute "source $DHCPD_TEMPLATE_FILE_" warn || \
        warn "Problems creating dhcpd config from \"$DHCPD_TEMPLATE_FILE_\""
    dhcpd3 -cf $DHCPD_CONFIG_FILE_ $BR_IFACE_ || warn "Problems starting dhcpd3 server"
}

function stopDhcpd
{
    local pid_="`ps aux |grep \"dhcpd3 .*$DHCPD_CONFIG_FILE_\" |grep -v \"grep dhcpd3 .*$DHCPD_CONFIG_FILE_\" |tr -s ' ' |awk '{print $2}'`"
    if [[ $pid_ == "" ]]; then
        warn "Could not find the dhcp server"
        return 1
    fi
    notice "killing \"$pid_\" (self=$$)"
    kill "$pid_" &>/dev/null
    sleep 1
    kill -9 "$pid_" &>/dev/null
}


function actionStart
{
    if [[ $BTPIN_ == "" ]]; then
        BTPIN_=$RANDOM
        warn "You don't gave me a pin, pin is: $BTPIN_"
    fi

    calcNetworkParams

    execute "brctl addbr $BR_IFACE_" || die "bridge grml-btnet already exists"
    execute "brctl stp $BR_IFACE_ off"
    execute "brctl sethello $BR_IFACE_ 0"
    execute "brctl setfd $BR_IFACE_ 0"
    execute "ifconfig $BR_IFACE_ $SERVER_IP_ netmask $NETMASK_ up"

    setPin "$BTPIN_"
    /etc/init.d/bluetooth start

    createDevUpScript
    pand -s --autozap --persist -r NAP
    startDhcpd
    $ENABLE_IPFORW_ && startIpForw
}

function actionStop
{
    pand -K
    killall pand &>/dev/null
    stopDhcpd
    killall -9 pand &>/dev/null
    /etc/init.d/bluetooth stop
    removeDevUpScript
    unsetPin

    ifconfig $BR_IFACE_ down
    brctl delbr $BR_IFACE_
    $ENABLE_IPFORW_ && stopIpForw
    echo "Stopped grml-btnets" >&2
}



###
### __MAIN
###

while getopts "s:i:p:hv" opt; do
    case "$opt" in
        s) NETWORK_="${OPTARG:-$NETWORK_}" ;;
        i) ENABLE_IPFORW_='true'
           FORWARD_IFACE_="${OPTARG:-$FORWARD_IFACE_}" ;;
        p) BTPIN_="${OPTARG:-$RANDOM}" ;;
        h) printUsage; exit 0 ;;
        v) let verbose_=$verbose_+1 ;;
        ?) printUsage; exit 64 ;;
    esac
done
shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
setVerbose $verbose_

case "$1" in
    help)   printUsage; exit 0 ;;
esac

checkRoot die "You have to be root to use this program"
disableSyslog


case "$1" in
    start) actionStart ;;
    stop) actionStop ;;
    "") actionStart ;;
    *) printUsage; exit 1;;
esac

exit 0

# END OF FILE
################################################################################
# vim:foldmethod=marker

