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