| 1 |
#!/bin/bash
|
| 2 |
# Copyright (c) 2004-2005 Gentoo Foundation
|
| 3 |
# Distributed under the terms of the GNU General Public License v2
|
| 4 |
|
| 5 |
# Contributed by Roy Marples (uberlord@gentoo.org)
|
| 6 |
|
| 7 |
# Fix any potential localisation problems
|
| 8 |
# Note that LC_ALL trumps LC_anything_else according to locale(7)
|
| 9 |
wpa_supplicant() {
|
| 10 |
LC_ALL=C /sbin/wpa_supplicant "$@"
|
| 11 |
}
|
| 12 |
|
| 13 |
wpa_cli() {
|
| 14 |
LC_ALL=C /bin/wpa_cli "$@"
|
| 15 |
}
|
| 16 |
|
| 17 |
# char* wpa_supplicant_provides(void)
|
| 18 |
#
|
| 19 |
# Returns a string to change module definition for starting up
|
| 20 |
wpa_supplicant_provides() {
|
| 21 |
echo "wireless"
|
| 22 |
}
|
| 23 |
|
| 24 |
# void wpa_supplicant_depend(void)
|
| 25 |
#
|
| 26 |
# Sets up the dependancies for the module
|
| 27 |
wpa_supplicant_depend() {
|
| 28 |
after macnet
|
| 29 |
before interface
|
| 30 |
}
|
| 31 |
|
| 32 |
# bool wpa_supplicant_check_installed(void)
|
| 33 |
#
|
| 34 |
# Returns 0 if wpa_supplicant is installed, otherwise 1
|
| 35 |
wpa_supplicant_check_installed() {
|
| 36 |
local report="${1:-false}" installed="0"
|
| 37 |
if [[ ! -x /sbin/wpa_supplicant ]]; then
|
| 38 |
installed="1"
|
| 39 |
${report} && eerror "For WPA support (wpa_supplicant) support, emerge net-wireless/wpa_supplicant"
|
| 40 |
fi
|
| 41 |
if [[ ! -e /proc/net/packet ]]; then
|
| 42 |
installed="1"
|
| 43 |
${report} && eerror "wpa_supplicant requires Packet Socket (CONFIG_PACKET=y) enabled in the kernel"
|
| 44 |
fi
|
| 45 |
return "${installed}"
|
| 46 |
}
|
| 47 |
|
| 48 |
# bool wpa_supplicant_check_depends(void)
|
| 49 |
#
|
| 50 |
# Checks to see if we have the needed functions
|
| 51 |
wpa_supplicant_check_depends() {
|
| 52 |
local f
|
| 53 |
|
| 54 |
for f in interface_exists; do
|
| 55 |
[[ $( type -t "${f}" ) == "function" ]] && continue
|
| 56 |
eerror "wpa_supplicant: missing required function ${f}\n"
|
| 57 |
return 1
|
| 58 |
done
|
| 59 |
|
| 60 |
return 0
|
| 61 |
}
|
| 62 |
|
| 63 |
# bool wpa_supplicant_check_extensions(char *interface)
|
| 64 |
#
|
| 65 |
# Checks to see if wireless extensions are enabled on the interface
|
| 66 |
wpa_supplicant_check_extensions() {
|
| 67 |
grep -q "^[ \t]*$1:[ \t]" /proc/net/wireless
|
| 68 |
}
|
| 69 |
|
| 70 |
# char* wpa_supplicant_get_essid(char *interface)
|
| 71 |
#
|
| 72 |
# Gets the current ESSID of iface
|
| 73 |
wpa_supplicant_get_essid() {
|
| 74 |
local i essid
|
| 75 |
|
| 76 |
for (( i=0; i<5; i++ )); do
|
| 77 |
essid=$( wpa_cli -i"$1" status | sed -n -e 's/^ssid=//p' )
|
| 78 |
if [[ -n ${essid} ]]; then
|
| 79 |
echo "${essid}"
|
| 80 |
return 0
|
| 81 |
fi
|
| 82 |
sleep 1
|
| 83 |
done
|
| 84 |
|
| 85 |
return 1
|
| 86 |
}
|
| 87 |
|
| 88 |
# char* wpa_supplicant_get_ap_mac_address(char *interface)
|
| 89 |
#
|
| 90 |
# Returns the MAC address of the Access Point
|
| 91 |
# the interface is connected to
|
| 92 |
wpa_supplicant_get_ap_mac_address() {
|
| 93 |
wpa_cli -i"$1" status | sed -n -e 's/^bssid=\([^=]\+\).*/\U\1/p'
|
| 94 |
}
|
| 95 |
|
| 96 |
# bool wpa_supplicant_associated(char *interface)
|
| 97 |
#
|
| 98 |
# Returns 0 if we're associated correctly or 1 if not
|
| 99 |
# Note that just because we are associated does not mean we are using the
|
| 100 |
# correct encryption keys
|
| 101 |
# We only need this for wpa_supplicant-0.3.x
|
| 102 |
wpa_supplicant_associated() {
|
| 103 |
local -a status=( "$( wpa_cli -i"$1" status | sed -n -e 's/^\(key_mgmt\|wpa_state\|EAP state\)=\([^=]\+\).*/\U\2/p' )" )
|
| 104 |
|
| 105 |
case "${status[0]}" in
|
| 106 |
"NONE") [[ ${status[1]} == "ASSOCIATED" ]] ;;
|
| 107 |
"IEEE 802.1X (no WPA)") [[ ${status[2]} == "SUCCESS" ]] ;;
|
| 108 |
*) [[ ${status[1]} == "COMPLETED" ]] ;;
|
| 109 |
esac
|
| 110 |
|
| 111 |
return $?
|
| 112 |
}
|
| 113 |
|
| 114 |
# void wpa_supplicant_kill(char *interface, bool report)
|
| 115 |
#
|
| 116 |
# Kills any existing wpa_supplicant process on the interface
|
| 117 |
wpa_supplicant_kill() {
|
| 118 |
local iface="$1" report="${2:-false}" pidfile
|
| 119 |
|
| 120 |
# Shutdown wpa_cli first, if it's running
|
| 121 |
# This is important as future versions of wpa_supplicant
|
| 122 |
# may send a disconnect message to wpa_cli when it shutsdown
|
| 123 |
pidfile="/var/run/wpa_cli-${iface}.pid"
|
| 124 |
if ! clean_pidfile "${pidfile}" ; then
|
| 125 |
${report} && ebegin "Stopping wpa_cli on ${iface}"
|
| 126 |
start-stop-daemon --stop --exec /bin/wpa_cli \
|
| 127 |
--pidfile "${pidfile}"
|
| 128 |
${report} && eend "$?"
|
| 129 |
fi
|
| 130 |
|
| 131 |
# Now shutdown wpa_supplicant
|
| 132 |
pidfile="/var/run/wpa_supplicant-${iface}.pid"
|
| 133 |
if ! clean_pidfile "${pidfile}" ; then
|
| 134 |
${report} && ebegin "Stopping wpa_supplicant on ${iface}"
|
| 135 |
start-stop-daemon --stop --exec /sbin/wpa_supplicant \
|
| 136 |
--pidfile "${pidfile}"
|
| 137 |
${report} && eend "$?"
|
| 138 |
else
|
| 139 |
# Support wpa_supplicant-0.3.x
|
| 140 |
local pid=$( pgrep -f '^/sbin/wpa_supplicant .* -i'"${iface}"'[ ]*$' )
|
| 141 |
if [[ -n ${pid} ]]; then
|
| 142 |
${report} && ebegin "Stopping wpa_supplicant on ${iface}"
|
| 143 |
kill -s TERM "${pid}"
|
| 144 |
${report} && eend 0
|
| 145 |
fi
|
| 146 |
fi
|
| 147 |
|
| 148 |
# If wpa_supplicant exits uncleanly, we need to remove the stale dir
|
| 149 |
[[ -S "/var/run/wpa_supplicant/${iface}" ]] \
|
| 150 |
&& rm -f "/var/run/wpa_supplicant/${iface}"
|
| 151 |
}
|
| 152 |
|
| 153 |
# bool wpa_supplicant_associate(char *interface)
|
| 154 |
#
|
| 155 |
# Returns 0 if wpa_supplicant associates and authenticates to an AP
|
| 156 |
# otherwise, 1
|
| 157 |
wpa_supplicant_associate() {
|
| 158 |
local iface="$1" ifvar=$( bash_variable "$1" ) timeout i
|
| 159 |
eval timeout=\"\$\{associate_timeout_${ifvar}\}\"
|
| 160 |
[[ -z ${timeout} ]] && eval timeout=\"\$\{wpa_timeout_${ifvar}:-60\}\"
|
| 161 |
|
| 162 |
[[ ${timeout} == "0" ]] \
|
| 163 |
&& vewarn "WARNING: infinite timeout set for association on ${iface}"
|
| 164 |
|
| 165 |
while true ; do
|
| 166 |
if ${action} ; then
|
| 167 |
service_started "net.${iface}" && return 0
|
| 168 |
else
|
| 169 |
if ! wpa_cli -i"${iface}" status &>/dev/null ; then
|
| 170 |
eend 1 "wpa_supplicant has exited unexpectedly"
|
| 171 |
return 1
|
| 172 |
fi
|
| 173 |
wpa_supplicant_associated "${iface}" && return 0
|
| 174 |
fi
|
| 175 |
sleep 1
|
| 176 |
(( i++ ))
|
| 177 |
[[ ${i} == "${timeout}" || ${i} -gt "${timeout}" ]] && break
|
| 178 |
done
|
| 179 |
|
| 180 |
# Spit out an appropriate error
|
| 181 |
if [[ ${background} != "yes" ]]; then
|
| 182 |
if ${action} ; then
|
| 183 |
eend 1 "Failed to configure ${iface} in the background"
|
| 184 |
else
|
| 185 |
eend 1 "Timed out"
|
| 186 |
fi
|
| 187 |
fi
|
| 188 |
|
| 189 |
# exit without error with wpa_supplicant-0.4.x as we may get kickstarted
|
| 190 |
# when an AP comes in range
|
| 191 |
${action} && exit 0
|
| 192 |
|
| 193 |
# Kill wpa_supplicant for 0.3.x
|
| 194 |
wpa_supplicant_kill "${iface}"
|
| 195 |
return 1
|
| 196 |
}
|
| 197 |
|
| 198 |
# bool wpa_supplicant_pre_start(char *interface)
|
| 199 |
#
|
| 200 |
# Start wpa_supplicant on an interface and wait for association
|
| 201 |
# Returns 0 (true) when successful, non-zero otherwise
|
| 202 |
wpa_supplicant_pre_start() {
|
| 203 |
local iface="$1" opts timeout action=false
|
| 204 |
local cfgfile="/etc/wpa_supplicant.conf"
|
| 205 |
local actfile="/sbin/wpa_cli.action"
|
| 206 |
|
| 207 |
# We don't configure wireless if we're being called from
|
| 208 |
# the background
|
| 209 |
if ${IN_BACKGROUND} ; then
|
| 210 |
ESSID=$( wpa_supplicant_get_essid "${iface}" )
|
| 211 |
ESSIDVAR=$( bash_variable "${ESSID}" )
|
| 212 |
save_options "ESSID" "${ESSID}"
|
| 213 |
return 0
|
| 214 |
fi
|
| 215 |
|
| 216 |
save_options "ESSID" ""
|
| 217 |
|
| 218 |
# We only work on wirelesss interfaces
|
| 219 |
wpa_supplicant_check_extensions "${iface}" || return 0
|
| 220 |
|
| 221 |
# Kill off any existing wpa_supplicant on this interface
|
| 222 |
# This is so we can re-read the configuration file and clean any stale
|
| 223 |
# directories
|
| 224 |
wpa_supplicant_kill "${iface}" true
|
| 225 |
|
| 226 |
# Check for rf_kill - only ipw supports this at present, but other
|
| 227 |
# cards may in the future
|
| 228 |
if [[ -e "/sys/class/net/${iface}/device/rf_kill" ]]; then
|
| 229 |
if [[ $( < "/sys/class/net/${iface}/device/rf_kill" ) != 0 ]]; then
|
| 230 |
eerror "Wireless radio has been killed for interface ${iface}"
|
| 231 |
return 1
|
| 232 |
fi
|
| 233 |
fi
|
| 234 |
|
| 235 |
# If wireless-tools is installed, try and apply our user config
|
| 236 |
# This is needed for some drivers - such as hostap because they start
|
| 237 |
# the card in Master mode which causes problems with wpa_supplicant.
|
| 238 |
if [[ $( type -t iwconfig_defaults ) == "function" ]]; then
|
| 239 |
iwconfig_defaults "${iface}"
|
| 240 |
iwconfig_user_config "${iface}"
|
| 241 |
fi
|
| 242 |
|
| 243 |
ebegin "Starting wpa_supplicant on ${iface}"
|
| 244 |
|
| 245 |
if [[ ! -f ${cfgfile} ]]; then
|
| 246 |
eend 1 "configuration file ${cfgfile} not found!"
|
| 247 |
return 1
|
| 248 |
fi
|
| 249 |
|
| 250 |
local ctrl_dir=$( sed -n -e 's/[ \t]*#.*//g;s/[ \t]*$//g;s/^ctrl_interface=//p' "${cfgfile}" )
|
| 251 |
if [[ ${ctrl_dir} != "/var/run/wpa_supplicant" ]]; then
|
| 252 |
eerror "${cfgfile} must set"
|
| 253 |
eerror " ctrl_interface=/var/run/wpa_supplicant"
|
| 254 |
eend 1
|
| 255 |
return 1
|
| 256 |
fi
|
| 257 |
|
| 258 |
local ifvar=$( bash_variable "${iface}" )
|
| 259 |
eval opts=\" \$\{wpa_supplicant_${ifvar}\}\"
|
| 260 |
[[ ${opts} != *" -D"* ]] \
|
| 261 |
&& ewarn "wpa_supplicant_${ifvar} does not define a driver"
|
| 262 |
|
| 263 |
# Some drivers require the interface to be up
|
| 264 |
interface_up "${iface}"
|
| 265 |
|
| 266 |
version=$( wpa_cli -v | sed -n -e 's/wpa_cli v//p' )
|
| 267 |
version=( ${version//./ } )
|
| 268 |
(( version = version[0] * 1000 + version[1] * 100 + version[2] ))
|
| 269 |
|
| 270 |
# wpa_supplicant 0.4.0 and greater supports wpa_cli actions
|
| 271 |
# This is very handy as if and when different association mechanisms are
|
| 272 |
# introduced to wpa_supplicant we don't have to recode for them as
|
| 273 |
# wpa_cli is now responsible for informing us of success/failure.
|
| 274 |
# The downside of this is that we don't see the interface being configured
|
| 275 |
# for DHCP/static.
|
| 276 |
if [[ ${version} -gt 399 && -x ${actfile} ]]; then
|
| 277 |
opts="${opts} -W -P/var/run/wpa_supplicant-${iface}.pid"
|
| 278 |
action=true
|
| 279 |
[[ ${RC_PARALLEL_STARTUP} == "yes" ]] && background=no
|
| 280 |
fi
|
| 281 |
|
| 282 |
start-stop-daemon --start --exec /sbin/wpa_supplicant \
|
| 283 |
-- ${opts} -B -c/etc/wpa_supplicant.conf -i"${iface}"
|
| 284 |
eend "$?" || return 1
|
| 285 |
|
| 286 |
# Starting wpa_supplication-0.4.0, we can get wpa_cli to
|
| 287 |
# start/stop our scripts from wpa_supplicant messages
|
| 288 |
if ${action} ; then
|
| 289 |
mark_service_inactive "net.${iface}"
|
| 290 |
ebegin "Starting wpa_cli on ${iface}"
|
| 291 |
start-stop-daemon --start --exec /bin/wpa_cli \
|
| 292 |
-- -a"${actfile}" -i"${iface}" \
|
| 293 |
-P"/var/run/wpa_cli-${iface}.pid" -B
|
| 294 |
eend "$?" || return 1
|
| 295 |
fi
|
| 296 |
|
| 297 |
# Background wpa_supplication if required
|
| 298 |
if [[ ${background} == "yes" ]]; then
|
| 299 |
if ! ${action} ; then
|
| 300 |
wpa_supplicant_associate "${iface}" \
|
| 301 |
&& export IN_BACKGROUND=true \
|
| 302 |
&& /etc/init.d/net.${iface} start >/dev/null &
|
| 303 |
fi
|
| 304 |
go_background
|
| 305 |
fi
|
| 306 |
|
| 307 |
eindent
|
| 308 |
veinfo "Waiting for association"
|
| 309 |
eend 0
|
| 310 |
|
| 311 |
wpa_supplicant_associate "${iface}" || return 1
|
| 312 |
|
| 313 |
# Set ESSID for essidnet and report
|
| 314 |
ESSID=$( wpa_supplicant_get_essid "${iface}" )
|
| 315 |
ESSIDVAR=$( bash_variable "${ESSID}" )
|
| 316 |
save_options "ESSID" "${ESSID}"
|
| 317 |
|
| 318 |
local -a status=( "$( wpa_cli -i${iface} status | sed -n -e 's/^\(bssid\|pairwise_cipher\|key_mgmt\)=\([^=]\+\).*/\U\2/p' | tr '[:lower:]' '[:upper:]' )" )
|
| 319 |
einfo "${iface} connected to \"${ESSID//\\\\/\\\\}\" at ${status[0]}"
|
| 320 |
|
| 321 |
if [[ ${status[2]} == "NONE" ]]; then
|
| 322 |
if [[ ${status[1]} == "NONE" ]]; then
|
| 323 |
ewarn "not using any encryption"
|
| 324 |
else
|
| 325 |
veinfo "using ${status[1]}"
|
| 326 |
fi
|
| 327 |
else
|
| 328 |
veinfo "using ${status[2]}/${status[1]}"
|
| 329 |
fi
|
| 330 |
eoutdent
|
| 331 |
|
| 332 |
if ${action} ; then
|
| 333 |
local addr=$( interface_get_address "${iface}" )
|
| 334 |
einfo "${iface} configured with address ${addr}"
|
| 335 |
exit 0
|
| 336 |
fi
|
| 337 |
|
| 338 |
return 0
|
| 339 |
}
|
| 340 |
|
| 341 |
# bool wpa_supplicant_post_stop(char *iface)
|
| 342 |
#
|
| 343 |
# Stops wpa_supplicant on an interface
|
| 344 |
# Returns 0 (true) when successful, non-zero otherwise
|
| 345 |
wpa_supplicant_post_stop() {
|
| 346 |
! ${IN_BACKGROUND} && wpa_supplicant_kill "$1" true
|
| 347 |
return 0
|
| 348 |
}
|
| 349 |
|
| 350 |
# vim:ts=4
|