# etc/wlan/shared
#
# Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
# --------------------------------------------------------------------
#
# linux-wlan
#
#   The contents of this file are subject to the Mozilla Public
#   License Version 1.1 (the "License"); you may not use this file
#   except in compliance with the License. You may obtain a copy of
#   the License at http://www.mozilla.org/MPL/
#
#   Software distributed under the License is distributed on an "AS
#   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
#   implied. See the License for the specific language governing
#   rights and limitations under the License.
#
#   Alternatively, the contents of this file may be used under the
#   terms of the GNU Public License version 2 (the "GPL"), in which
#   case the provisions of the GPL are applicable instead of the
#   above.  If you wish to allow the use of your version of this file
#   only under the terms of the GPL and not to allow others to use
#   your version of this file under the MPL, indicate your decision
#   by deleting the provisions above and replace them with the notice
#   and other provisions required by the GPL.  If you do not delete
#   the provisions above, a recipient may use your version of this
#   file under either the MPL or the GPL.
#
# --------------------------------------------------------------------
#
# Inquiries regarding the linux-wlan Open Source project can be
# made directly to:
#
# AbsoluteValue Systems Inc.
# info@linux-wlan.com
# http://www.linux-wlan.com
#
# --------------------------------------------------------------------
#
# Portions of the development of this software were funded by 
# Intersil Corporation as part of PRISM(R) chipset product development.
#
# --------------------------------------------------------------------

if [ -x /sbin/wlanctl-ng ] ; then 
	WLANCTL=/sbin/wlanctl-ng
else
	echo "wlanctl-ng not found."
	exit 1
fi

# Source the wlan configuration
if [ -f /etc/wlan/wlan.conf ] ; then
	. /etc/wlan/wlan.conf
else
	echo "/etc/wlan/wlan.conf not found."
	exit 0
fi

is_true ()
{
	# $1 == string containing a t/f indicator.

	[ "$1" = "y" -o "$1" = "Y" -o "$1" = "yes" -o "$1" = "YES" ]
}

wlan_enable ()
{
	# $1 == wlandev

 	#=======ENABLE IFSTATE=============================
 	# Bring the device into its operable state
	
	# First, make sure the driver is loaded....
	if ! ifconfig $1 2>&1 > /dev/null ; then
		echo "Error: Device $1 does not seem to be present."
		echo "Make sure you've inserted the appropriate"
		echo "modules or that your modules.conf file contains"
		echo "the appropriate aliase(s)."
		return 1
	fi

	# Enable the interface
	result=`$WLANCTL $1 lnxreq_ifstate ifstate=enable`
	if [ $? = 0 ] ; then
		eval $result
		if [ $resultcode != "success" ]; then
			echo "Failed to enable the device, resultcode=" \
				$resultcode "."
			return 1
		fi
	else
		echo "Failed to enable the device, exitcode=" $? "."
		return 1
	fi
}

wlan_user_mibs ()
{
	# $1 == wlandev

	#=======USER MIB SETTINGS=============================
	# Set the user specified MIB items.
	for i in $USER_MIBS ; do
		result=`$WLANCTL $1 dot11req_mibset "mibattribute=$i"`
		if [ $? = 0 ] ; then
			eval $result
			if [ $resultcode != "success" ] ; then 
				echo "Failed to set user MIB $i."
				return 1
			fi
		else
			echo "Failed to set user MIB $i."
			return 1
		fi
	done
}

wlan_source_config ()
{
	# $1 == wlandev 

	# XXX what about stray singlequotes.
	eval 'GOSSID="$SSID_'$1'"'
	wlan_source_config_for_ssid "$GOSSID"
}

wlan_source_config_for_ssid ()
{
	# $1 == ssid[:BSSID]

	DesiredSSID="$1"

	if [ X"$1" != X"" ] ; then
		token_ssid=`echo $1 | sed -ne 's/\(.*\)\(:..:..:..:..:..:..\).*/\1/p'`
		token_bssid=`echo $1 | sed -ne 's/\(.*\):\(..:..:..:..:..:..\).*/\2/p'`
	fi

        if [ X"$token_ssid" != X"" ] ; then
                DesiredSSID="$token_ssid"
                DesiredBSSID=$token_bssid
        fi

	if [ -f "/etc/wlan/wlancfg-$1" ] ; then
		. "/etc/wlan/wlancfg-$1"
	elif [ -f "/etc/wlan/wlancfg-$DesiredSSID" ] ; then
		. "/etc/wlan/wlancfg-$DesiredSSID"
	else 

		if [ X"$1" != X"" ] ; then
			echo "Failed to open network config file /etc/wlan/wlancfg-$1, using default."
		fi

		. "/etc/wlan/wlancfg-DEFAULT"
	fi
}

wlan_disable ()
{
	# $1 == wlandev
	$WLANCTL $1 lnxreq_ifstate ifstate=disable
}	

wlan_download ()
{
	result=`$WLANCTL $1 lnxreq_ifstate ifstate=disable`
	if [ $? = 0 ] ; then
		eval $result
		if [ $resultcode != "success" ]; then
			echo "Failed to disable the device, resultcode=" \
				$resultcode "."
			return 1
		fi
	else
		echo "Failed to disable the device, exitcode=" $? "."
		return 1
	fi

	result=`$WLANCTL $1 lnxreq_ifstate ifstate=fwload`
	if [ $? = 0 ] ; then
		eval $result
		if [ $resultcode != "success" ]; then
			echo "Failed to enable the device, resultcode=" \
				$resultcode "."
			return 1
		fi
	else
		echo "Failed to enable the device, exitcode=" $? "."
		return 1
	fi

	#=======DOWNLOAD======================================
	# If the card needs code/data downloaded, do it.
	if ! $WLAN_DOWNLOADER -r $WLAN_DLIMAGE $1 ; then
		echo "Code/Data Download Failed."
		return 1
	fi

	# re-enable the device.
	wlan_enable $1
}

wlan_ssid_in_list ()
{
	# $1 == wlandev, $2 == ssid,  $3 == bssid

	# XXX what about stray singlequotes.
	eval 'GOSSID="$SSID_'$1'"'
	
	# This "eval" hackery is to allow escapes in GOSSID...
	cmd="for token in $GOSSID ; do
		ssid_token=\`echo \"\$token\" | sed -ne 's/\(.*\)\(:..:..:..:..:..:..\).*/\1/p'\`
		bssid_token=\`echo \"\$token\" | sed -ne 's/\(.*\):\(..:..:..:..:..:..\).*/\2/p'\`

		if [ \"X\$ssid_token\" = X ] ; then
			ssid_token="\$token"
		fi

		if [ \"X\$bssid_token\" != X ] ; then
			if [ \"\$bssid_token\" = \"\$3\" ] ; then
				return 0
			fi
		elif [ \"\$2\" = \"\$ssid_token\" ] ; then
			return 0	
		fi
	done"
	eval "$cmd"

	return 1
}

wlan_supports_scan ()
{
	# $1 == wlandev

	if is_true "$WLAN_SCAN" ; then
		cat /proc/net/p80211/$1/wlandev | grep 'scan' > /dev/null
		if [ $? = 0 ] ; then
			return 0
		fi
	fi
	return 1
}

wlan_scan ()
{
	# $1 == wlandev

	# find our allowed SSID list.
	
	# XXX what about stray singlequotes.
	eval 'GOSSID="$SSID_'$1'"'

	# if our list is null, then scan for anything!
	
	if [ "$GOSSID" = "" ] ; then
		wlan_scan_one $1 
		if [ $? = 0 ] ; then
			return 0
		fi
	fi;

	# otherwise we walk through the list, and scan for eacn in turn.
	# this "eval" hackery is to allow escapes in GOSSID
	cmd="for token in $GOSSID ; do
		ssid_token=\`echo \"\$token\" | sed -ne 's/\(.*\)\(:..:..:..:..:..:..\).*/\1/p'\`
		bssid_token=\`echo \"\$token\" | sed -ne 's/\(.*\):\(..:..:..:..:..:..\).*/\2/p'\`

		if [ \"X\$ssid_token\" = X ] ; then
			ssid_token=\"\$token\"
		fi

		wlan_scan_one \$1 \"\$ssid_token\" \"\$bssid_token\"
		if [ \$? = 0 ] ; then
			return 0
		fi
	done"
	eval "$cmd"

	# We got to the end of the list.  Maybe try "any"
	if is_true "$WLAN_ANY" ; then
		wlan_scan_one $1 
		return $?
	fi


	return 1
}


wlan_scan_one ()
{
	# $1 == wlandev ( $2 == ssid, $3 == bssid ), optional

	numbss=0

	result=`$WLANCTL $1 dot11req_scan bsstype=any bssid=ff:ff:ff:ff:ff:ff \
		scantype=both probedelay=0 channellist=$ChannelList ssid="$2" \
		minchanneltime=$ChannelMinTime maxchanneltime=$ChannelMaxTime`
	eval $result
	if [ $resultcode != 'success' ] ; then
		echo "Scan failed ($resultcode) "
		return 1
	fi
	
	i=0
	bssfound=""

	# walk through the results and do first-cut matching.

	while [ $i -lt $numbss ] ; do
		result=`$WLANCTL $1 dot11req_scan_results bssindex=$i`
		eval $result

		if [ X"$3" != X"" ] ; then
			if [ "$3" = "$bssid" ] ; then
				bssfound="$bssfound $i"
			fi
		elif [ X"$2" = X"" ] ; then
			# if our ssid is "", then we pick the first entry.
			bssfound="$bssfound $i"
		elif [ "$2" = "$ssid" ] ; then
			bssfound="$bssfound $i"
		else
			bssfound="$bssfound $i"
		fi
		i=`expr $i + 1`
	done

	if [ "-$bssfound-" = "--" ]; then       # No BSSs found, bail.
		return 1
	else
		# Now find the closest
		bigsignal=0
		for i in $bssfound ; do
			result=`$WLANCTL $1 dot11req_scan_results bssindex=$i`
			eval $result
			if [ $bigsignal -lt $signal ]; then
				bigsignal=$signal
				bigbssindex=$i
			fi
		done
		result=`$WLANCTL $1 dot11req_scan_results bssindex=$bigbssindex`
		eval $result

		return 0
	fi
}

wlan_wep ()
{
	#=======WEP===========================================
	# Setup privacy
	result=`$WLANCTL $1 dot11req_mibget mibattribute=dot11PrivacyOptionImplemented`
	if [ $? = 0 ] ; then
		eval $result
		eval $mibattribute
	else
		echo "dot11PrivacyOptionImplemented mibget failed."
		return 1
	fi

	if [ $dot11PrivacyOptionImplemented = "false" -a \
	     $dot11PrivacyInvoked = "true" ] ; then
		echo "Cannot enable privacy, dot11PrivacyOptionImplemented=false."
		return 1
	fi

	# Do we want host-based WEP?
	result=`$WLANCTL $1 lnxreq_hostwep \
	    decrypt="${lnxreq_hostWEPDecrypt:-false}"    \
	    encrypt="${lnxreq_hostWEPEncrypt:-false}"  `

	# set up the rest of the parametsrs.
	if [ $dot11PrivacyOptionImplemented = "true" -a \
	     $dot11PrivacyInvoked = "true" ] ; then
		$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11WEPDefaultKeyID=$dot11WEPDefaultKeyID
		$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11ExcludeUnencrypted=$dot11ExcludeUnencrypted
		$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11PrivacyInvoked=$dot11PrivacyInvoked
		if [ "${PRIV_GENSTR:-empty}" != "empty" ] ; then
			if [ ${PRIV_KEY128:-"false"} = "false" ]; then
				keys=`$PRIV_GENERATOR "$PRIV_GENSTR" 5`
			else
				keys=`$PRIV_GENERATOR "$PRIV_GENSTR" 13`
			fi
				knum=0
			for i in $keys ; do
				$WLANCTL $1 dot11req_mibset \
				mibattribute=dot11WEPDefaultKey$knum=$i
				knum=$[$knum + 1]
			done
		else 
			$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11WEPDefaultKey0=$dot11WEPDefaultKey0 
			$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11WEPDefaultKey1=$dot11WEPDefaultKey1
			$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11WEPDefaultKey2=$dot11WEPDefaultKey2
			$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11WEPDefaultKey3=$dot11WEPDefaultKey3
		fi
	else
		# disable wep explicitly.
		$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11PrivacyInvoked=$dot11PrivacyInvoked
		$WLANCTL $1 dot11req_mibset \
			mibattribute=dot11ExcludeUnencrypted=false
	fi
}

wlan_adhoc ()
{
	#=======IBSS STARTUP==================================
	startcmd="$WLANCTL $1 dot11req_start "
	startcmd="$startcmd ssid=$DesiredSSID"
	startcmd="$startcmd bsstype=independent"
	startcmd="$startcmd beaconperiod=$BCNINT" 
	startcmd="$startcmd dtimperiod=3"
	startcmd="$startcmd cfpollable=false"
	startcmd="$startcmd cfpollreq=false"
	startcmd="$startcmd cfpperiod=3"
	startcmd="$startcmd cfpmaxduration=100"
	startcmd="$startcmd probedelay=100"
	startcmd="$startcmd dschannel=$CHANNEL"
	j=1
	for i in $BASICRATES ; do
		startcmd="$startcmd basicrate$j=$i"
		j=$[j + 1]
		done

	j=1
	for i in $OPRATES ; do
		startcmd="$startcmd operationalrate$j=$i"
		j=$[j + 1]
	done

	results=`$startcmd`	# Here's where it runs
	if [ $? = 0 ]; then 
		eval $results
		if [ $resultcode != "success" ] ; then 
			echo "IBSS not started, resultcode=$resultcode"
			exit 1
		else
			echo "IBSS mode started."
		fi
	else
		echo FAILED: $startcmd
		return 1
	fi
	WLAN_SCHEMESSID="$DesiredSSID"
}

wlan_infra ()
{
	#==== INFRASTRUCURE STARTUP===========================
	# XXX TODO:  Grok DesiredBSSID

	results=`$WLANCTL $1 lnxreq_autojoin \
		"ssid=$DesiredSSID" \
		authtype=${AuthType:="opensystem"} | sed 's/\([^=]*\)=\(.*\)/\1="\2"/'`
	eval $results
	if [ ${resultcode:-"failure"} != "success" ] ; then
		echo 'error: Autojoin indicated failure!'
		return 1;
	fi

	WLAN_SCHEMESSID="$DesiredSSID"
}

wlan_dot11_join ()
{
	joincmd="$WLANCTL $1 dot11req_join bssid=$DesiredBSSID"
	joincmd="$joincmd joinfailuretimeout=1"
	
	j=1
	for i in $OPRATES ; do
		joincmd="$joincmd operationalrate$j=$i"
		j=$[j + 1]
	done

	results=`$joincmd`

	eval $results
	if [ ${resultcode:-"failure"} != "success" ] ; then
		echo 'error:  dot11req_join failed!'
		return 1;
	fi

	if [ $bsstype = "infrastructure" ] ; then 
		results=`$WLANCTL $1 dot11req_authenticate \
				peerstaaddress=$DesiredBSSID \
				authenticationtype=$AuthType \
				authenticationfailuretimeout=2000`
		eval $results
		if [ ${resultcode:-"failure"} != "success" ] ; then
			echo "error:  dot11req_authenticate failed, "\
				"resultcode=$resultcode"
			return 1;
		fi
		results=`$WLANCTL $1 dot11req_associate \
				listeninterval=1000 \
				associatefailuretimeout=2000 `
		if [ ${resultcode:-"failure"} != "success" ] ; then
			echo 'error:  dot11req_associate failed!'
			return 1;
		fi
	fi
}

wlan_set_ssid_schemefile ()
{
	# Find the scheme file 
	if [ -r /var/lib/misc/pcmcia-scheme ] ; then
		# Debian
		WLAN_SCHEMEFILE="/var/lib/misc/pcmcia-scheme"
	elif [ -d /var/state/pcmcia ] ; then
		WLAN_SCHEMEFILE="/var/state/pcmcia/scheme"
	elif [ -d /var/lib/pcmcia ] ; then
        	WLAN_SCHEMEFILE="/var/lib/pcmcia/scheme"
	else
		WLAN_SCHEMEFILE="/var/run/pcmcia-scheme"
	fi

	# Collect the current scheme name and save the file
	if [ -r $WLAN_SCHEMEFILE ] ; then
		WLAN_SCHEME=`cat $WLAN_SCHEMEFILE`
		cp $WLAN_SCHEMEFILE /tmp/wlan_scheme_`date +"%T"`.tmp
	else
		touch /tmp/wlan_scheme_`date +"%T"`.tmp
		
	fi

	# Set up the <scheme:SSID> string
	if [ ! "$WLAN_SCHEME" ] ; then 
		WLAN_SCHEME="default"
	fi
	WLAN_SCHEME="$WLAN_SCHEME:$1"

	# Write to schemefile
	echo $WLAN_SCHEME > $WLAN_SCHEMEFILE
}

wlan_restore_schemefile ()
{
	# Find the scheme file 
	if [ -r /var/lib/misc/pcmcia-scheme ] ; then
		WLAN_SCHEMEFILE="/var/lib/misc/pcmcia-scheme"
	elif [ -d /var/state/pcmcia ] ; then
		WLAN_SCHEMEFILE="/var/state/pcmcia/scheme"
	elif [ -d /var/lib/pcmcia ] ; then
        	WLAN_SCHEMEFILE="/var/lib/pcmcia/scheme"
	else
		WLAN_SCHEMEFILE="/var/run/pcmcia-scheme"
	fi

	TMPFILE=`ls /tmp/wlan_scheme*.tmp | tail -n 1`

	if [ -r $TMPFILE ] ; then
		cat $TMPFILE > $WLAN_SCHEMEFILE
		rm -f $TMPFILE
	else
		echo "wlan_restore_schemefile: No wlan_scheme\*.tmp file found."
	fi
}
