#!/bin/sh
# The purpose of this script is to maintain a wlan conenction.
# Requires ping, iwconfig, with english output.

# pseudocode..
#if !ping {
#  if essid=off/any > set_essid
#  if essid=invalid > associate
#  if failure > reload driver

#  if !associated {
#    set_essid
#    if !associated {
#      reload_driver
#    }
#  } elseif currentRate != wantedRate {
#    setRate(wantedRate);
#  }
#}

###[ configuration ]###

iface=eth1	# wireless interface
essid="NETGEAR"	# AP's identity
rate=11M	# desired rate setting
freq="2.442"
chan=7
localAddr=192.168.0.1	# An address to ping on the local network,
			# preferrably your wlan-router/ap
remoteAddr=82.182.16.1	# An address to ping outside your LAN, i.e ISP router

###[ script code ]###

# ping address in arg 1
gotPing() {
  numReceived=$(ping -n -c1 -I $iface $1|grep -o -E '[0-9]{1,} received' |grep -o -E '[0-9]{1,}')
  if [ $numReceived != 0 ]; then
    echo 1;
  else
    echo 0;
  fi
}

info() {
  echo "Info: $@"
}

getCurrentRate() {
  # extract current wlan rate
  currentRate=$(iwconfig $iface 2>&1|grep -o -E 'Bit Rate=[0-9]{1,}'|grep -o -E '[0-9]{1,2}')M
}

# restores wlan rate to $rate if it has changed
maintainRate() {
  getCurrentRate
  if [ "$currentRate" != "$rate" ]; then
    info "Rate changed to $currentRate, restoring to $rate"
    iwconfig eth1 rate $rate
  fi
}

checkAssociation() {
  invalidAP=$(iwconfig eth1 2>&1|grep -o -E 'Access Point:.{1,}'|grep -o -E 'Invalid')
  if [ "$invalidAP" = "Invalid" ]; then
    info "Not associated, attempting reconnect"
    reconnect
  fi
}

reconnect() {
  ## reload broadcom wireless driver
  reconnectFailCount=`expr $reconnectFailCount + 1`;
  echo $reconnectFailCount connection attempts
  if [ $reconnectFailCount = 3 ]; then
    echo 3 failed reconnection attempts, Reloading bcm43xx driver!
    ifdown $iface && modprobe -r bcm43xx && modprobe bcm43xx && ifup $iface
    reconnectFailCount=0
  fi
  iwconfig $iface essid off
  iwconfig $iface freq $freq
  iwconfig $iface channel $chan
  iwconfig $iface essid $essid
  sleep 0.1
  iwconfig $iface rate $rate
  sleep 0.1
  iwconfig $iface rate $rate
  sleep 0.1
  dhclient -1 $iface
  echo Sleeping for 3 seconds
  sleep 3
}

i=0
localPingFailCount=0
reconnectFailCount=0
#while [ 1 -eq 1]; do	# run eternally
while [ $i != 2 ]; do
#  i=`expr $i + 1`;
#  echo "debug: main loop";
  checkAssociation
  maintainRate
  res=$(gotPing $localAddr)
  if [ "$res" = "0" ]; then
    localPingFailCount=`expr $localPingFailCount + 1`;
    echo $localPingFailCount failed pings
    if [ $localPingFailCount = 3 ]; then
      reconnect
      localPingFailCount=0
    fi
  fi
  if [ "$res" = "1" ]; then
    localPingFailCount=0
    reconnectFailCount=0
    echo All OK!
  fi
  sleep 1	# sleep for 500ms
done
