An elegant way to set wifi interface up with wpa_supplicant during boot process

Eloi Primaux eloi at bliscat.org
Fri Mar 10 05:41:19 PST 2006


AUTHOR: Eloi Primaux eloi AT bliscat dot org

DATE: 2006-02-19

LICENSE: GNU Free Documentation License Version 2

SYNOPSIS: An elegant way to set wifi interface up with wpa_supplicant
during boot time

DESCRIPTION:
This hint follow the way of how network lfs's services are built to
create an wpa-supplicant network service
which is able to read wpa_supplicant.conf file format to set wifi
interface up during system boot process


ATTACHMENTS:


PREREQUISITES:
You will need a fully well configured LFS-6.1 (at least) system
you will also need to read this hint:
http://www.linuxfromscratch.org/hints/downloads/files/wireless.txt
Thus you need :
	1 ==> The driver(s) of your wireless interface (http://madwifi.org/wiki
for Atheros chipsets (some NETGEAR use it))
	2 ==> The "wireless tools" (needed sometimes if not released with your
driver(s))
	3 ==> The "wpa_supplicant" program (which is a daemon plus an ui)
version 0.4.8 required (0.4.7 hangs up too much time)

note those three requested programs/drivers can easily be installed
using their README files and wikis
please read the documentation of wpa_supplicant to know how to define a
network

HINT:
This hint is the second release and it should be used instead of
"Setting a wireless network with WPA and dhcpcd"
which is obsolete and completely bugged (thanks to myself...)

First of all, create the following files

The wpa_supplicant boot-script

	in /etc/rc.d/init.d
	make it executable chmod 755 /etc/rc.d/init.d/wpa_supplicant
	link it to your desired init level
	example :
	ln -s /etc/rc.d/init.d/wpa_supplicant /etc/rc.d/rc3.d/S15wpa_supplicant
(network is K20)
	ln -s /etc/rc.d/init.d/wpa_supplicant /etc/rc.d/rc5.d/S15wpa_supplicant
(network is K20)
	ln -s /etc/rc.d/init.d/wpa_supplicant /etc/rc.d/rc0.d/K75wpa_supplicant
(network is K80 for me)
	ln -s /etc/rc.d/init.d/wpa_supplicant /etc/rc.d/rc6.d/K65wpa_supplicant
(network is K60 for me)


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#!/bin/sh
# Begin $rc_base/init.d/wpa_supplicant

# Based on:
#sysklogd script from LFS-6.1 and earlier.
#dhcpcd service script from LFS-6.1.1
# Rewritten by Eloi Primaux

#$LastChangedBy: eloi $
#$Date: 2006-03-10 -1243 (Fri, 10 mar 2006) $

. /etc/sysconfig/rc
. $rc_functions
. /etc/profile

WPA_GLOBAL_FILE=/var/run/wpa_supplicant-global
WPA_ACCESS_DIR=/var/run/wpa_supplicant
WPA_PID_FILE=/var/run/wpa_supplicant.pid
WPA_CONFIG_FILE=/etc/sysconfig/network-devices/wpa_supplicant/wpa_supplicant.conf

#wpa_supplicant process must be unique


case "$1" in
	start)
		boot_mesg "Starting wpa_supplicant..."
		if [ -f "$WPA_PID_FILE" ]
                then
                ps `cat "$WPA_PID_FILE"` | grep wpa_supplicant
> /dev/null
                    if [ $? != 0 ]
                    then
		   	ps -C wpa_supplicant | grep wpa_supplicant > /dev/null
			if [  $? != 0 ]
			then
			boot_mesg "killing old wpa_supplicant daemon..." ${WARNING}
                   	echo_warning
			 while [ -n "$(ps -C wpa_supplicant | grep wpa_supplicant )" ]
			 do
			 killall wpa_supplicant
			 done
		         rm -fr $WPA_GLOBAL_FILE $WPA_PID_FILE $WPA_ACCESS_DIR
> /dev/null
			fi
                   else
		   boot_mesg "wpa_supplicant already running!" ${WARNING}
                   echo_warning
                   exit 2
                   fi
		else
			ps -C wpa_supplicant | grep wpa_supplicant > /dev/null
			if [  $? != 0 ]
			then
			boot_mesg "killing old wpa_supplicant daemon..." ${WARNING}
                   	echo_warning
			 i=1
			 while [ i != 0 ]
			 do
			 ps -C wpa_supplicant | grep wpa_supplicant > /dev/null
			 i=$?
			 killall wpa_supplicant > /dev/null
			 done
		         rm -fr $WPA_GLOBAL_FILE $WPA_PID_FILE $WPA_ACCESS_DIR
> /dev/null
			fi
        	fi
			wpa_supplicant -g$WPA_GLOBAL_FILE -P$WPA_PID_FILE -B

		;;

	stop)
		boot_mesg "Stopping wpa_supplicant..."
		i=1
		while [ i != 0 ]
		do
		ps -C wpa_supplicant | grep wpa_supplicant > /dev/null
		i=$?
		killall wpa_supplicant
		done
		rm -fr $WPA_GLOBAL_FILE $WPA_PID_FILE $WPA_ACCESS_DIR > /dev/null

		;;


	restart)
		$0 stop
		sleep 5
		$0 start
		;;

	*)
		echo "Usage: $0 {start|stop|restart}"
		exit 1
		;;
esac

# End $rc_base/init.d/wpa_supplicant
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The wpa_supplicant service file

	in /etc/sysconfig/network-devices/services
	make it executable chmod
755 /etc/sysconfig/network-devices/services/wpa_supplicant

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#!/bin/bash
# Begin $network-devices/services/wpa-dhcpcd

# Based on dhcpcd script adapted for wpa networks with or without dhcp
support
# Rewritten by Eloi Primaux  - eloi AT bliscat DOT org
# 2006-02-20 First script, wpa_supplicant was launched here, one
wpa_supp per interface
# 2006-02-21 Only one instance of wpa_supplicant for all interfaces,
completely rewritten
# 2006-02-22 lot of bugs fixed, now it uses the wpa_supplicant.conf
format.
# 2006-03-10 optimizing for (speed) boot process , just set interface up
and let wpa_supp alone
#		This is the light version (no debug mode) mail me to receive the
worst one... ;)
#This service REQUIRE the wpa_supplicant daemon running!
#Which MUST be launched with the appropriate boot script


. /etc/sysconfig/rc
. $rc_functions
. $IFCONFIG

#This is LFS specific
	SERVICES_DIRECTORY="/etc/sysconfig/network-devices/services"
# here is the socket file of wpa_supplicant pseudo network
	WPA_GLOBAL_FILE="/var/run/wpa_supplicant-global"
	WPA_GLOBAL_DIR="/var/run/wpa_supplicant"
case "$2" in
        up)

# Beautifying....
	echo -n "" # due to the pre ifconfig process

# Non stupid ad-dons...
# example : if there is no network available...
# So...



# Here we add the wifi wpa interface, eg 'ifconfig up' but in wpa way

# Add a new interface (no configuration file and enable control
interface)
RET=`$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE interface_add $1 "" $WPA_DRIVER
$WPA_GLOBAL_DIR`
# Reading the wpa config file
grep -v '#' $WPA_CONFIG_DIR/$WPA_CONFIG_FILE | while read line
do
	if [ "$line" = "network={" ]; then
		# creating a new network configuration, saving network number to
NETWORK
		NETWORK=`$WPA_CLIENT_NAME -i$1 add_network`
	else
	  	if [ "$line" = "}" ]; then
	  	# now the network is configured, enabling it
          	RET=`$WPA_CLIENT_NAME -i$1 enable_network $NETWORK`
	  	else
			if [ -n "$( echo "$line" |  grep -v "ctrl_interface")" ]; then
			# all others lines should be network parameters...
			# i need to replace the first '=' character by a pace
			line="`echo "$line" | sed 's,=, ,'`"
#For debugging (it's always here due to strings substitution) 
#				echo "setting parameter : $line"
#				echo "$WPA_CLIENT_NAME -i$1 set_network $NETWORK $line"
			echo "$WPA_CLIENT_NAME -i$1 set_network $NETWORK $line" | sh
> /dev/null # FIX-ME !!!
			fi
		fi
	fi
done


# When the network is ready wpa_supplicant will answer
"wpa_state=COMPLETED"
# thus we will wait until connection is established to launch the ip
service

RET="`$WPA_CLIENT_NAME -i$1 status | grep 'wpa_state' | cut -f2- -d=`"
# we run a little loop to wait for wpa_supplicant being ready before
launch ip service
# to not loop indefinitely at boot time if the network is down...
COUNTER=0
$(while [ "$RET" != "COMPLETED" ]
do let COUNTER=$COUNTER+1; if [ "$COUNTER" = "$WPA_MAXCYCLE" ]; then
boot_mesg "interface $1 Timeout " ${WARNING}; $0 remove; exit 2; fi
sleep 5s; RET="`$WPA_CLIENT_NAME -i$1 status | grep 'wpa_state' | cut
-f2- -d=`"  || exit 1
 $SERVICES_DIRECTORY/$IP_SERVICE_NAME $1 up > /dev/null ; done ) &


        ;;

        down)

	$SERVICES_DIRECTORY/$IP_SERVICE_NAME $1 down
	$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE disconnect $1 > /dev/null
	$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE interface_remove $1 > /dev/null

        ;;

	remove)
	$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE disconnect $1 > /dev/null
	$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE interface_remove $1 > /dev/null
	;;
        *)
                echo "Usage: $0 [interface] {up|down}"
                exit 1
        ;;
esac

# End $network_devices/services/wpa-dhcpcd
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




And now the network config file: named wpa_supplicant

	in /etc/sysconfig/network-devices/ifconfig.DEVICE where DEVICE is your
device name (like ath0,eth1,wlan1,2..)

example : /etc/sysconfig/network-devices/ifconfig.ath0/wpa_supplicant

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/etc/sysconfig/network-devices/ifconfig.ath0/wpa_supplicant ONBOOT="yes"
SERVICE="wpa_supplicant"

# the ip settings (note: only the debug version will print something)
        IP_SERVICE_NAME="dhcpcd" # or ipv4-static ... copy their conf
here
        DHCP_START="-d "
        DHCP_STOP="-k "
        # Set PRINTIP="yes" to have the script print
        # the DHCP assigned IP address
        PRINTIP="no"
        # Set PRINTALL="yes" to print the DHCP assigned values for
        # IP, SM, DG, and 1st NS. This requires PRINTIP="yes".
        PRINTALL="no"

# The wpa settings

	#the name of the wpa_supplicant client if it changes
        WPA_CLIENT_NAME="wpa_cli"
        # here is the directory where wpa_supplicant.conf should be
        WPA_CONFIG_DIR="/etc/sysconfig/wpa_supplicant"
        # here is the name of your wpa_supplicant.conf file
        WPA_CONFIG_FILE="wpa_supplicant.conf"

# Here you have to define which wpa driver wpa_supplicant will use for
this interface
        WPA_DRIVER="madwifi"

# To avoid boot freezing on this service (truly true with the debug
version)
# one cycle each 5 seconds
        WPA_MAXCYCLE=10

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

And then, the wpa_supplicant file:

	according to the file created above it should be in the $WPA_CONFIG_DIR
	and named $WPA_CONFIG_FILE

	example /etc/sysconfig/wpa_supplicant/wpa_supplicant.conf

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Begin wpa_supplicant configuration file
# it's just an example but all information are in wpa_supplicant README,
read it please
network={
	ctrl_interface=/var/run/wpa_supplicant
	ssid='"ESSID"' # please quote '""' when you have a space character
	scan_ssid=1
	key_mgmt=WPA-PSK
	proto=WPA2
	pairwise=CCMP
	group=CCMP
	psk='"Your password"' # please quote '""' when you have a space
character
}
# End of wpa_supplicant configuration file
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


Because you read all these lines, i'm gonna give you the "little bugged"
debug version
but it is fully usable (i've set my network with it)

Same as the wpa_supplicant service
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#!/bin/bash
# Begin $network-devices/services/wpa-dhcpcd

# Based on dhcpcd script adapted for wpa networks with or without dhcp
support
# Rewritten by Eloi Primaux  - eloi AT bliscat DOT org
# 2006-02-20 First script, wpa_supplicant was launched here, one
wpa_supp per interface
# 2006-02-21 Only one instance of wpa_supplicant for all interfaces,
completely rewritten
# 2006-02-22 lot of bugs fixed, now it uses the wpa_supplicant.conf
format.

#This service REQUIRE the wpa_supplicant daemon running!
#Which MUST be launched with the appropriate boot script


. /etc/sysconfig/rc
. $rc_functions
. $IFCONFIG

#This is LFS specific
	SERVICES_DIRECTORY="/etc/sysconfig/network-devices/services"
# here is the socket file of wpa_supplicant pseudo network
	WPA_GLOBAL_FILE="/var/run/wpa_supplicant-global"
	WPA_GLOBAL_DIR="/var/run/wpa_supplicant"
case "$2" in
        up)

# Beautifying....
	echo -n "" # due to the pre ifconfig process

# Non stupid ad-dons...
# example : if there is no network available...
# So...



# Here we add the wifi wpa interface, eg 'ifconfig up' but in wpa way

RET=`$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE interface_add $1 "" $WPA_DRIVER
$WPA_GLOBAL_DIR`
	boot_mesg "Scanning ESSID(s) from interface $1..."
	SSID_AVAILABLE=`echo -n $(iwlist $1 scan | grep 'ESSID' | cut -f2-
-d:)`
	REGISTRED_AVAILABLE_ESSID=""
	REGISTRED_ESSID=`echo -n $(cat $WPA_CONFIG_DIR/$WPA_CONFIG_FILE | grep
'ssid=' | grep -v 'scan_ssid=' | cut -f2- -d=)`
	echo "$SSID_AVAILABLE"

	for ESSID in $SSID_AVAILABLE; do
		if [ -n `echo $REGISTRED_ESSID | grep $ESSID` ]; then
			REGISTRED_AVAILABLE_ESSID="$REGISTRED_AVAILABLE_ESSID $ESSID "
		fi
	done
	
	if [ -n "$REGISTRED_AVAILABLE_ESSID" ]; then
		boot_mesg "Found known ESSID(s) :"
		boot_mesg "$REGISTRED_AVAILABLE_ESSID"
		echo_ok
		# Add a new interface (no configuration file and
		# enable control interface)


# The fact is: one connection alive per interface... but
# this never tells that we can only define one network...
# Thus here a while loop to read the wpa configuration file

grep -v '#' $WPA_CONFIG_DIR/$WPA_CONFIG_FILE | while read line; do

	if [ "$line" = "network={" ]; then
	# creating a new network configuration, saving network number to
NETWORK
		echo "adding network"
NETWORK=`$WPA_CLIENT_NAME -i$1 add_network`
	else
		if [ "$line" = "}" ]; then
	# now the network is configured, enabling it
RET=`$WPA_CLIENT_NAME -i$1 enable_network $NETWORK`
		else
			if [ -n "$( echo "$line" |  grep -v "ctrl_interface")" ]; then
	# all others lines should be network parameters...

	# i need to replace the first '=' character by a pace
				line="`echo "$line" | sed 's,=, ,'`"
#For debugging (it's always here due to strings substitution) 
#				echo "setting parameter : $line"
#				echo "$WPA_CLIENT_NAME -i$1 set_network $NETWORK $line"
echo "$WPA_CLIENT_NAME -i$1 set_network $NETWORK $line" | sh > /dev/null
# FIX-ME !!!
			fi
		fi
	fi
done


# When the network is ready wpa_supplicant will answer
"wpa_state=COMPLETED"

RET="`$WPA_CLIENT_NAME -i$1 status | grep 'wpa_state' | cut -f2- -d=`"
		# we run a little loop to wait for wpa_supplicant being ready
		boot_mesg "Connecting to the most secure and available ESSID..."
		# to not loop indefinitely at boot time if the network is down...
		COUNTER=0
		while [ "$RET" != "COMPLETED" ]; do
		let COUNTER=$COUNTER+1
			if [ "$COUNTER" = "$WPA_MAXCYCLE" ]; then
			boot_mesg "Some Access Points are available" ${WARNING}
			boot_mesg "But the connection time is over . This is" ${WARNING}
			boot_mesg "mostly due to a misconfigurated network." ${WARNING}
			boot_mesg "Please check your configuration" ${WARNING}
                        echo_warning
                        exit 2
		fi
			sleep 5s
RET="`$WPA_CLIENT_NAME -i$1 status | grep 'wpa_state' | cut -f2- -d=`"
|| exit 1
			echo -n "$RET.."
        	done
		echo ""
		echo_ok
		
		#Launching the ip service
		$SERVICES_DIRECTORY/$IP_SERVICE_NAME $1 up
	else
		boot_mesg "The Access Point "$WPA_SSID" is not available" ${WARNING}
		boot_mesg "Please check your configuration" ${WARNING}
                        echo_warning
                        exit 2
	fi

        ;;

        down)

	$SERVICES_DIRECTORY/$IP_SERVICE_NAME $1 down
	$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE disconnect $1 > /dev/null
	$WPA_CLIENT_NAME -g$WPA_GLOBAL_FILE interface_remove $1 > /dev/null

        ;;

        *)
                echo "Usage: $0 [interface] {up|down}"
                exit 1
        ;;
esac

# End $network_devices/services/wpa-dhcpcd

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ACKNOWLEDGEMENTS:
 the wireless hint (very well writed compare to mine)
 wpa_supplicant http://hostap.epitest.fi/wpa_supplicant
 madwifi wiki http://madwifi.org/
 and more and more
	thanks to everyone i read to set up my wireless network


CHANGELOG:
2006 03 10 Second release, first send to lfshint




More information about the hints mailing list