#!/bin/bash
#--------------------------------------------------------------------------------
# INFO:
# This small shell script performs setup/restart capability for my wireless
# card for various networks.
# The various functions are listed first...the actual start point is at
# the bottom of the script.
#
#--------------------------------------------------------------------------------
# This script is Copyright (c) 2004 Shawn E. Delahunty, All Rights Reserved.
#
# It is released as FREE SOFTWARE under the terms and conditions of
# the GNU General Public License.
#
# Please refer to the Free Software Foundation website for details of
# the GNU GPL.  http://www.gnu.org
#--------------------------------------------------------------------------------


#----------------------------------------------------------------------------
# This function OUGHT to be pretty self explanatory...
#----------------------------------------------------------------------------
function ShowHelp()
{
	echo " This script must be run as follows:"
	echo "  "$0" <network>  (ex. "$0" home)"
	echo
	echo "      This script requires ONE of the following network descriptions:"
	echo "  home       -  restart wireless card for HOME network"
	echo "  office     -  restart wireless to access office"
	echo "  sev     -  restart wireless card for severino's wireless access!"
	echo
	echo "  scan       -  Listen for any available access points"
	echo
	echo "  stop       -  Safely shutdown wireless card & services"
	echo "  off        -  Safely shutdown wireless card & services"
	echo
	echo "    (NOTE: You must be ROOT to execute this script properly.)"
	echo
	return 0
}


#----------------------------------------------------------------------------
# Try to shut down the specified ethernet interface in a graceful fashion
#----------------------------------------------------------------------------
function Stop_Ethernet_Interface()
{
	local TEST_RESULT=""

	echo "   - shutting down "$ENET_INTERFACE_NAME" (if active)"
	ifconfig $ENET_INTERFACE_NAME down
	TEST_RESULT=$?
	if [ $TEST_RESULT -eq 1 ] ; then
		echo "  ** ERROR! ** Unable to shutdown interface "$ENET_INTERFACE_NAME
		echo
		return 1
	fi
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# Set up the primary wireless parameters for the NIC.  Gracefully handle
# any errors encountered during the attempt.
#----------------------------------------------------------------------------
function Configure_Wireless_Params()
{
	local TEST_RESULT=""

	echo "   - configuring wireless parameters"
	
	# See if the ESSID specified for this network matches one that's available
	# from a visible access-point.
	TEST_RESULT=$($IWLIST_CMD $ENET_INTERFACE_NAME scan 2>/dev/null | 
		grep -v grep | grep -c $ESSID)
	if [ $TEST_RESULT -eq 0 ] ; then
		echo " ** ERROR! ** Cannot find the access-point for "$ESSID"!!"
		echo "  Halting."
		echo
		return 1
	fi
	
	$IWCONFIG_CMD $ENET_INTERFACE_NAME mode Managed
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo "  ** ERROR! ** Unable to set Wireless mode!"
		echo
		return 1
	fi

	$IWCONFIG_CMD $ENET_INTERFACE_NAME essid $ESSID
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo "  ** ERROR! ** Unable to perform "$IWCONFIG_CMD" for ESSID properly!"
		echo
		return 1
	fi

	$IWCONFIG_CMD $ENET_INTERFACE_NAME enc $WEP_KEY
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo "  ** ERROR! ** Unable to perform "$IWCONFIG_CMD" for WEP key properly!"
		echo
		return 1
	fi

#	$IWCONFIG_CMD $ENET_INTERFACE_NAME 
	
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# Specify that the ethernet interface for the wireless lan card should used
# DHCP to obtain it's IP & such.
#----------------------------------------------------------------------------
function Configure_Ethernet_DHCP()
{
	local TEST_RESULT=""

	$DHCPCD_CMD $ENET_INTERFACE_NAME
	TEST_RESULT=$?
	if [ $TEST_RESULT -eq 1 ] ; then
		echo "  ** ERROR! ** Unable to perform "$DHCPCD_CMD" properly!"
		echo
		return 1
	fi
	sleep 1
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# This function manually configures the IP for the wireless lan card.
#----------------------------------------------------------------------------
function Configure_Ethernet_FixedIP()
{
	local TEST_RESULT=""

	echo "   - Setting static IP: "$FIXED_IP
	ifconfig $ENET_INTERFACE_NAME $FIXED_IP netmask $NETMASK
	TEST_RESULT=$?
	if [ $TEST_RESULT -eq 1 ] ; then
		echo "  ** ERROR! ** Unable to perform IFCONFIG for manual IP!"
		echo
		return 1
	fi
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# This should contain all the hoo-haa necessary to shutdown the given ethernet interface,
# configure the wireless card, and bring things back up, including good DHCP of
# the IP information.
#----------------------------------------------------------------------------
function Start_DHCP_Network()
{
	echo "Setting up wireless card for "$NETWORK_NAME" network with DHCP..."

	Stop_Ethernet_Interface
	if [ $? -ne 0 ] ; then
		return 1
	fi
	sleep 1

	Configure_Wireless_Params
	if [ $? -ne 0 ] ; then
		return 1
	fi
	sleep 1

	echo "   - trying to obtain DHCP information...(max "$DHCP_TIMEOUT" seconds)"
	Configure_Ethernet_DHCP
	if [ $? -ne 0 ] ; then
		return 1
	fi

	echo "  ..done."
	echo
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# This should contain all the hoo-haa necessary to shutdown the given ethernet interface,
# configure the wireless card, and bring things back up, including good configuration of
# the IP info.
#----------------------------------------------------------------------------
function Start_FixedIP_Network()
{
	echo "Setting up wireless card for "$NETWORK_NAME" network..."

	Stop_Ethernet_Interface
	if [ $? -ne 0 ] ; then
		return 1
	fi
	sleep 1

	Configure_Wireless_Params
	if [ $? -ne 0 ] ; then
		return 1
	fi
	sleep 1

	Configure_Ethernet_FixedIP
	if [ $? -ne 0 ] ; then
		return 1
	fi
	sleep 1

	echo "  ..done."
	echo
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
function Setup_OfficeNet()
{
	NETWORK_NAME="Office"
	WEP_KEY="CHANGEME"
	ESSID="CHANGEME"
#	FIXED_IP="192.168.1.132"
#	NETMASK="255.255.255.0"
#	Start_FixedIP_Network

	Start_DHCP_Network
	if [ $? -ne 0 ] ; then
			return 1
	fi
	
	# Add any mounts here...
	
	echo "done."
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
function Setup_Home_Network()
{
	NETWORK_NAME="Ryan's Home Network"
	WEP_KEY="CHANGEME"
	ESSID="CHANGEME"
	Start_DHCP_Network
	if [ $? -ne 0 ] ; then
		return 1
	fi

#	FIXED_IP="10.0.0.57"
#	NETMASK="255.255.0.0"
#	Start_FixedIP_Network

	return 0
}

#----------------------------------------------------------------------------
# This attempts to set up a completely OPEN connection to the DHCP router
# at the local sev shop.
#----------------------------------------------------------------------------
function Setup_Sev_Network()
{
	NETWORK_NAME="Sev's Wireless (Airport Express)"
	WEP_KEY="CHANGEME"
#	WEP_KEY="off"
#	ESSID="default"
	ESSID="CHANGEME"

	Start_DHCP_Network
	if [ $? -ne 0 ] ; then
		return 1
	fi
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# This attempts an UMOUNT of any NFS drives that have been mounted.
# If we fail, print a warning and return a fail code to the parent/caller function.
#----------------------------------------------------------------------------
function Unmount_NFS_Drives()
{
	local UMOUNTRESULT=""

	echo -n "Unmounting any NFS drives..."
	umount -a -t nfs 2>/dev/null
	UMOUNTRESULT=$?
	if [ $UMOUNTRESULT -ne 0 ] ; then
		echo "** ERROR! Cannot UNMOUNT NFS drives!"
		echo
		echo "You may have a prompt or process open from an NFS volume."
		echo "You will have to close that out before the wireless link"
		echo "can be altered."
		echo
		return 1
	fi
	echo "done."
	# If we get here, all is well.
	return 0
}


#----------------------------------------------------------------------------
# This attempts to find a running instance of the DHCP client daemon in the
# task list that is tied to a prior invocation for this wlan0 interface.
# If we find one, kill it off...we will respawn later.
#----------------------------------------------------------------------------
function Remove_DHCPCD()
{
	local STUFF=""

	STUFF=$(ps aux | grep -v grep | grep -c "dhcpcd")
	if [ $STUFF -ne 0 ] ; then
		STUFF=$(ps aux | grep -v grep |
			grep "$DHCPCD_CMD -t $DHCP_TIMEOUT $ENET_INTERFACE_NAME" | awk  '{print $2}')
		kill -TERM $STUFF
	fi

	return 0
}


#----------------------------------------------------------------------------
# This simply performs a proper shutdown of the card.  It does a stop on
# net interface, the shuts down all PCMCIA slots.
#----------------------------------------------------------------------------
function Shutdown_Wireless()
{
	local TEST_RESULT=""

	echo -n "Shutting down wireless..."
	Stop_Ethernet_Interface
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo " ERROR!"
		echo "  Unable to shutdown logical interface: "$ENET_INTERFACE_NAME
		return 1
	fi

	$IWCONFIG_CMD $ENET_INTERFACE_NAME txpower off 2>/dev/null
	sleep 1

	# Destroy the occurrence of DHCPCD in the task list...
	# I may want to pull this OUT of here later, once things are behaving...
	Remove_DHCPCD

	echo "done."

	return 0
}


#----------------------------------------------------------------------------
# Simply handle the various legal arguments to this script.  For anything else,
# let the tard know they've mungled something.
#----------------------------------------------------------------------------
function Handle_Arguments()
{
	# Work out which argument we have & act accordingly
	case "$ARGONE" in
		office)
			Setup_OfficeNet
		;;

		home)
			Setup_Home_Network
		;;

		sev)
			Setup_Sev_Network
		;;

		stop)
			Shutdown_Wireless
		;;
		off)
			Shutdown_Wireless
		;;	

		*)
			echo
			echo "I don't grok parameter -->"$ARGONE"<-- at all..."
			echo
			ShowHelp
			return 1
		;;
	esac

	if [ $? -ne 0 ] ; then
		return 1
	fi
	# If we get here, whatever network option we tried to activate has worked...
	return 0
}


#----------------------------------------------------------------------------
# We do a little interrogation of the system/path to determine if all the
# various commands/scripts we need are available.  We redirect the stderr
# stuff to la-la-land, to keep things neat & pretty.
#----------------------------------------------------------------------------
function Check_For_Commands()
{
	local TEST_RESULT=""
	echo -n "Checking for required list of scripts/commands..."


	#DHCPCD_CMD=$(which dhcpcd 2>/dev/null)
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo " FAIL!"
		echo "  * Cannot locate the $DHCPCD_CMD command/script...halting."
		echo
		return 1
	fi

	#IWCONFIG_CMD=$(which iwconfig 2>/dev/null)
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo " FAIL!"
		echo "  * Cannot locate the $IWCONFIG_CMD command/script...halting."
		echo
		return 1
	fi

	IWLIST_CMD=$(which iwlist 2>/dev/null)
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo " FAIL!"
		echo "  * Cannot locate the 'iwlist' command/script...halting."
		echo
		return 1
	fi
	
	NDIS_DRIVER=$(which loadndisdriver 2>/dev/null)
	TEST_RESULT=$?
	if [ $TEST_RESULT -ne 0 ] ; then
		echo " FAIL!"
		echo "  * Cannot locate the NDIS driver!...halting."
		echo
		return 1
	fi

	# If we get here, all is well.
	echo "ok."
	return 0
}


#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
function Check_For_Windrivers()
{
	echo -n "Checking for presence of Windows-Driver files for NDIS..."
	if [ -f $INF_FILE ] && [ -f $SYS_FILE ] ; then
		echo "done!"
		return 0
	fi
	echo "*ERROR!*"
	echo "Cannot find the Windows-Driver files!  Halting."
	return 1
}



#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
function Check_For_Root()
{
	local RESULT1=""

	echo -n "Checking user level..."
	RESULT1=$(whoami)
	if [ "$RESULT1" != "root" ] ; then
		echo "FAILED!"
		echo "  Sorry Charlie....you must be GOD to run this script."
		echo
		return 1
	fi
	# If we get here, all is well.
	echo "ok."
	return 0
}


#----------------------------------------------------------------------------
# Function to check if the wireless radio itself has been turned on.  There is
# almost CERTAINLY a better/more accurate way to do this, via /proc or something,
# but this seems to work for now...
#
# If we see "No scan results", we interpret that to mean the radio is OFF.
#----------------------------------------------------------------------------
function Check_For_AccessPoints()
{
	local RESULT1=""

	echo -n "Checking Radio status and available AP's..."
	# This seems like a duplication, but it's proving necessary as a kind of
	# 'dummy' starter command for our first power-up of the Broadcom card.
	sleep 3
	$IWLIST_CMD $ENET_INTERFACE_NAME scan 1>/dev/null 2>/dev/null

	RESULT1=$($IWLIST_CMD $ENET_INTERFACE_NAME scan 2>/dev/null | 
		grep -v grep | grep -c "No scan results")
	if [ $RESULT1 -ne 0 ] ; then
		echo "FAILED!"
		echo "  Radio is OFF, or access-point is unavailable."
		echo
		return 1
	fi
	# If we get here, all is well.
#	sleep 2
	echo "ok."
	echo "  Access points seen:"
	$IWLIST_CMD $ENET_INTERFACE_NAME scan 2>/dev/null | 
		grep -v grep | grep "ESSID:" 
	return 0

}


#----------------------------------------------------------------------------
# This function attempts to find the specified device in the PCI space.
#----------------------------------------------------------------------------
function Check_Device_Present()
{
	local RESULT1=""
	echo -n "Checking for presence of "$ENET_INTERFACE_NAME"..."

	RESULT1=$(lspci | grep -v grep | grep -c 'BCM4306')
	if [ $RESULT1 -ne 0 ] ; then
		RESULT1=$(lspci -n | grep -v grep | grep 'Class 0280' | awk  '{print $4}')
		VENDOR_ID=$(echo $RESULT1 | awk -F : '{print $1}')
		DEVICE_ID=$(echo $RESULT1 | awk -F : '{print $2}')
		echo "done!"
		return 0
	else
		echo "*ERROR!*"
		echo "Device not seen in PCI space!  Halting."
		return 1
	fi
}



###################################################################################################
#
#   A couple of GLOBALS, in case the script needs to be modified for other configurations
#
###################################################################################################
ENET_INTERFACE_NAME="wlan0"
DHCP_TIMEOUT=15

VENDOR_ID=""
DEVICE_ID=""
NDIS_DRIVER=""
SCRIPT_NAME=""
DHCPCD_CMD="dhclient"
IWCONFIG_CMD="iwconfig"
IWLIST_CMD="iwlist"
NDIS_DRIVER=""

INF_FILE="/lib/windrivers/net/bcmwl5a.inf"
SYS_FILE="/lib/windrivers/net/bcmwl5.sys"

####################################################################
#
#		SCRIPT EXECUTION BEGINS HERE!!!
#
####################################################################

# Neatness, neatness, neatness...
echo
SCRIPT_NAME=$0

# First, check to see if we have some kind of command line argument.
# If not, tell them how to use us properly...
#
# (This section is NOT in a function-call for a very good reason.
# For some reason we do *NOT* have access to the BASH arglist that is
# handed in to us within the scope of the functions...)
echo -n "Checking for arglist..."
if [ $1 ] ; then
	ARGONE=$1
	echo "ok."
else
	echo "FAIL!"
	echo
	ShowHelp
	exit 1
fi

# Next, see if we have been executed by ROOT...if not, EJECT EJECT EJECT!
Check_For_Root
if [ $? -ne 0 ] ; then
	exit 2
fi

# Check to see if the necessary commands for controlling the ENET interface and
# wireless card are available to us.
Check_For_Commands
if [ $? -ne 0 ] ; then
	exit 3
fi

# Check to see if the windows-driver files have been installed to the
# expected directory
Check_For_Windrivers
if [ $? -ne 0 ] ; then
	exit 4
fi

# Ensure the NDISWrapper module has been installed.
if [ $(lsmod | grep -v grep | grep -c ndiswrapper) -eq 0 ] ; then
	echo -n "Inserting NDISwrapper module..."
	modprobe ndiswrapper
	if [ $? -ne 0 ] ; then
		echo "FAIL!"
		echo " NDISwrapper module does not appear to be present!"
		echo " Please ensure you've built and installed it!"
		exit 5
	fi
	sleep 3
	echo "done."
fi

# See if an instance of the DHCP client daemon is already running for
# this interface.  If so, stop it...we'll be relaunching it.
Remove_DHCPCD
if [ $? -ne 0 ] ; then
	exit 6
fi

# Check if the specific device shows up in the PCI listing..
Check_Device_Present
if [ $? -ne 0 ] ; then
	exit 7
fi

# At this point, the wireless extensions are active & ready.  Check to see if
# the radio itself is ON by doing a scan...but not if we're going into SHUTDOWN.
# If we see "No scan results", we interpret that to mean the radio is OFF.
case "$ARGONE" in
	off)
	;;
	stop)
	;;
	scan)
		Check_For_AccessPoints
		exit 0
	;;
	*)
		Check_For_AccessPoints
		if [ $? -ne 0 ] ; then
			Unmount_NFS_Drives
			Shutdown_Wireless
			exit 8
		fi
	;;
esac

# For safety, make certain we've UMOUNT'd any NFS drives,
# in case we're switching away from a net-connection that has some mounted.
Unmount_NFS_Drives
if [ $? -ne 0 ] ; then
	Shutdown_Wireless
	exit 9
fi

# At last we're ready, process whatever argument(s) we received...
Handle_Arguments
if [ $? -ne 0 ] ; then
	Shutdown_Wireless
	exit 10
fi

# Show a successful command exit to BASH
exit 0

