summaryrefslogtreecommitdiffstats
path: root/rc.wireless
blob: b9713ade5b72c904f5f4420a54359cc438428eba (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
#!/bin/sh
# /etc/rc.d/rc.wireless
# $Id: rc.wireless,v 1.13 2007/04/13 14:14:43 eha Exp eha $
#
# Wireless network card setup.
#
# This script sets up PCI, USB, and 32-bit Cardbus wireless devices
# NOT 16-bit PCMCIA cards!  Those are configured in /etc/pcmcia/.
# Single parameter to this script is the name of a network interface.
# Normally this script is called from rc.inet1 rather than run
# directly.
#
# This script is a modified '/etc/pcmcia/wireless' script
# 09/apr/2004 by Eric Hameleers
# 16/sep/2004 * Eric Hameleers * Fixed iwspy and iwpriv commands
# 08/apr/2005 * Eric Hameleers * Allow per-interface overrides of the wireless
#                                parameters (see /etc/rc.d/rc.inet1.conf)
# 11/apr/2005 * Eric Hameleers * Tune wpa_supplicant interactions.
# 23/apr/2005 * Eric Hameleers * First configure card with iwconfig,
#                                before starting wpa_supplicant
# 27/apr/2005 * Eric Hameleers * Multiple 'iwpriv $INTERFACE set' commands.
# 14/feb/2006 * Eric Hameleers * Better error messages; alternative way of
#                                getting HWADDR; parametrized WPA_WAIT value.
#                                Don't kill an already running wpa_supplicant.
# 29/apr/2006 * Pat Volkerding * Reverted HWADDR change, since it relies on
#                                a binary (macaddr) that is not built or
#                                installed by default since it is not
#                                compatible with all interfaces.
# 15/aug/2006 * Eric Hameleers * Added missing "" around $ESSID, which broke
#                                ESSIDs that contain a space character.
# 10/oct/2006 * Eric Hameleers * Added default empty values for all parameters.
#                                This makes a second wireless card leave
#                                wpa_supplicant alone if WPA is not configured.
# 15/oct/2006 * Eric Hameleers * Swapped the calls to "key <key>" and
#                                "key restricted" since that might be needed
#                                for WEP to work reliably.
# 09/jan/2007 * Eric Hameleers * Add explicit default values to wireless params;
#                                also set the ESSID before IWPRIV commands,
#                                needed for some RaLink cards;
#                                use /proc/net/wireless instead of calling
#                                iwconfig to determine if a card is wireless.
# 13/apr/2007 * Eric Hameleers * Use of the IWPRIV variable was broken.
#                                NOTE: if you need to enter multiple parameters
#                                in IWPRIV, you must separate them with the pipe
#                                (|) character - this used to be a space char!
#                                See the example in rc.inet1.conf.
# 16/apr/2008 * Pat Volkerding * Make sure that HWADDR is all upper case.
# 23/apr/2008 * Pat Volkerding * Increase sleep time after bringing up an
#                                interface to 3 seconds.  Some drivers
#                                need this additional time to initalize.
# 02/jan/2010 * Pat Volkerding * Look for /sys/class/net/$NETDEV/wireless rather
#                                than the contents of /proc/net/wireless to find
#                                if a network device is wireless.  In newer
#                                kernels devices will not show up in
#                                /proc/net/wireless until active.
# 16/aug/2012 * Pat Volkerding * Use several tests to determine if an interface
#                                is wireless, as the reliability of any given
#                                test may depend on the kernel options and the
#                                wireless driver used.
#                                Convert the MAC address to uppercase in sed.
# 11/Nov/2019 * Darren Austin *  Log to syslog, failling back to stdout.
#                                Output error to stderr if not called from
#                                rc.inet1.
# 09/Mar/2021 * Darren Austin *  Don't leave the interface in an 'up' state upon
#                                exit from the script - this causes problems for
#                                SLAAC in rc.inet1 when control is returned.
# ------------------------------------------------------------------------------

# If possible, log events in /var/log/messages:
if [ -f /var/run/syslogd.pid ] && [ -x /usr/bin/logger ]; then
  LOGGER=/usr/bin/logger
else # output to stdout/stderr:
  LOGGER=/bin/cat
fi

if [ -z "$IFNAME" ] ; then
  echo "ERROR: The script 'rc.wireless' must be executed by 'rc.inet1'!" >&2
  echo "       You should run the command \"/etc/rc.d/rc.inet1 <your_interface>_start\" yourself." >&2
  return 1 2> /dev/null || exit 1
fi

INTERFACE=$1

# Find the path where wireless tools are installed
for IWPATH in /usr/{bin,sbin} /usr/local/{bin,sbin} /sbin /bin ; do
    if [ -x $IWPATH/iwconfig ] ; then break ; fi
done

# The same for wpa_supplicant (needed for WPA support)
for SUPPATH in /usr/{bin,sbin} /usr/local/{bin,sbin} /sbin /bin ; do
    if [ -x $SUPPATH/wpa_supplicant ] ; then break ; fi
done

# Set all desired settings through the wireless tools
IWCOMMAND="$IWPATH/iwconfig ${INTERFACE}"
IWPRIVCMD="$IWPATH/iwpriv ${INTERFACE}"
IWSPYCMD="$IWPATH/iwspy ${INTERFACE}"
IFCOMMAND="/sbin/ip link set dev ${INTERFACE}"

is_wireless_device ()
{
    # Return 0 for a wireless interface, or 1 for a non-wireless interface.
    if [ -d /sys/class/net/${1}/wireless ]; then
        return 0
    elif grep -Fxq 'DEVTYPE=wlan' /sys/class/net/${1}/uevent 2>/dev/null; then 
        return 0
    elif LC_ALL=C $IWPATH/iwconfig $1 2>&1 | grep -q "IEEE 802.11" ; then
        return 0
    else # all tests failed, assume the device is not wireless (or add a better test :)
        return 1
    fi
}

###############
# EXIT POINTS #
###############

# Is the device wireless?  If not, exit this script.
is_wireless_device ${INTERFACE} || return 0 2> /dev/null || exit 0

# If we stop a wireless interface using wpa_supplicant,
# we'll kill its wpa_supplicant daemon too and exit this script:
if [ "$2" = "stop" ]; then
	pkill --full "bin/wpa_supplicant.* -i${INTERFACE}"
	return 0
fi

# -----------------------------------------------------
# Continue with the script - bringing the interface UP.
# -----------------------------------------------------

# Bring interface up - for determining the HWADDR
$IFCOMMAND up
sleep 3

# Get the MAC address for the interface
HWADDR=$(cat "/sys/class/net/${INTERFACE}/address")

# Empty all wireless parameters- some of them could still be set for a previous interface:
# when rc.inet1 is sourced from rc.M all scripts are run in the same shell.
CHANNEL=""
ESSID=""
FREQ=""
FRAG=""
IWCONFIG=""
IWPRIV=""
IWSPY=""
KEY=""
MODE=""
NICKNAME=""
NWID=""
RATE=""
RTS=""
SENS=""
WPA=""
WPADRIVER=""
WPACONF=""
WPAWAIT=""
# Read the configuration information for the card with address $HWADDR
# from /etc/rc.d/rc.wireless.conf:
[[ -r /etc/rc.d/rc.wireless.conf ]] && . /etc/rc.d/rc.wireless.conf

# Let any per-interface overrides (the WLAN_xxxx parameters) that are set
# in /etc/rc.d/rc.inet1.conf have precedence.
# The reason: you might have multiple wireless cards of the same brand, or
# connecting to multiple networks.
# Position 'i' of this interface in the IFNAME array was determined in rc.inet1
CHANNEL=${WLAN_CHANNEL[$i]:-${CHANNEL}}
ESSID=${WLAN_ESSID[$i]:-${ESSID}}
FREQ=${WLAN_FREQ[$i]:-${FREQ}}
FRAG=${WLAN_FRAG[$i]:-${FRAG}}
IWCONFIG=${WLAN_IWCONFIG[$i]:-${IWCONFIG}}
IWPRIV=${WLAN_IWPRIV[$i]:-${IWPRIV}}
IWSPY=${WLAN_IWSPY[$i]:-${IWSPY}}
KEY=${WLAN_KEY[$i]:-${KEY}}
MODE=${WLAN_MODE[$i]:-${MODE}}
NICKNAME=${WLAN_NICKNAME[$i]:-${NICKNAME}}
NWID=${WLAN_NWID[$i]:-${NWID}}
RATE=${WLAN_RATE[$i]:-${RATE}}
RTS=${WLAN_RTS[$i]:-${RTS}}
SENS=${WLAN_SENS[$i]:-${SENS}}
WPA=${WLAN_WPA[$i]:-${WPA}}
# The "ext" interface will be default if not explicitly set
WPADRIVER=${WLAN_WPADRIVER[$i]:-${WPADRIVER:="wext"}}
# The default config file as installed by the wpa_supplicant package:
WPACONF=${WLAN_WPACONF[$i]:-${WPACONF:="/etc/wpa_supplicant.conf"}}
WPAWAIT=${WLAN_WPAWAIT[$i]:-${WPAWAIT:="60"}}


[ -n "$VERBOSE" ] && [ -n "$INFO" ] && echo "$0:  $1 information: '$INFO'"

###################
# WIRELESS CONFIG #
###################

# Mode needs to be first : some settings apply only in a specific mode!
if [ -n "$MODE" ] ; then
	echo "$0:  $IWCOMMAND mode $MODE" | $LOGGER
        # if $IWCOMMAND fails, try taking the interface down to run it.
        # Some drivers require this.
	if ! $IWCOMMAND mode $MODE 2> /dev/null ; then
		$IFCOMMAND down
		$IWCOMMAND mode $MODE
		$IFCOMMAND up
		sleep 3
        fi
fi
# This is a bit hackish, but should do the job right...
if [ ! -n "$NICKNAME" ] ; then
    NICKNAME=$(/bin/hostname)
fi
if [ -n "$ESSID" ] || [ -n "$MODE" ] ; then
	echo "$0:  $IWCOMMAND nick $NICKNAME" | $LOGGER
	$IWCOMMAND nick $NICKNAME
fi
# Regular stuff...
if [ -n "$NWID" ] ; then
	echo "$0:  $IWCOMMAND nwid $NWID" | $LOGGER
	$IWCOMMAND nwid $NWID
fi
if [ -n "$FREQ" ] ; then
	echo "$0:  $IWCOMMAND freq $FREQ" | $LOGGER
	$IWCOMMAND freq $FREQ
elif [ -n "$CHANNEL" ] ; then
	echo "$0:  $IWCOMMAND channel $CHANNEL" | $LOGGER
	$IWCOMMAND channel $CHANNEL
fi

# WEP keys (non-WPA) 
if [ -n "$KEY" ] && [ ! -n "$WPA" ] ; then
	if [ "$KEY" = "off" ]; then
	  echo "$0:  $IWCOMMAND key open" | $LOGGER
	  $IWCOMMAND key open
	  echo "$0:  $IWCOMMAND key off" | $LOGGER
	  $IWCOMMAND key off
	else 
	  echo "$0:  $IWCOMMAND key ************" | $LOGGER
	  $IWCOMMAND key $KEY
	  if ! echo "$KEY" | egrep -qw "restricted|open" ; then
	    # Set "restricted" as the default security mode:
	    echo "$0:  $IWCOMMAND key restricted" | $LOGGER
	    $IWCOMMAND key restricted
	  fi
	fi
fi
if [ -n "$SENS" ] ; then
	echo "$0:  $IWCOMMAND sens $SENS" | $LOGGER
	$IWCOMMAND sens $SENS
fi
if [ -n "$RATE" ] ; then
	echo "$0:  $IWCOMMAND rate $RATE" | $LOGGER
	$IWCOMMAND rate $RATE
fi
if [ -n "$RTS" ] ; then
	echo "$0:  $IWCOMMAND rts $RTS" | $LOGGER
	$IWCOMMAND rts $RTS
fi
if [ -n "$FRAG" ] ; then
	echo "$0:  $IWCOMMAND frag $FRAG" | $LOGGER
	$IWCOMMAND frag $FRAG
fi
# More specific parameters
if [ -n "$IWCONFIG" ] ; then
	echo "$0:  $IWCOMMAND $IWCONFIG" | $LOGGER
	$IWCOMMAND $IWCONFIG
fi
if [ -n "$IWSPY" ] ; then
	echo "$0:  $IWSPYCMD $IWSPY" | $LOGGER
	$IWSPYCMD $IWSPY
fi
# For RaLink cards, the SSID must be set right before configuring WPAPSK/TKIP parameters
# using iwpriv commands in order to generate the wpapsk password. This should not hurt other cards:
if [ -n "$ESSID" ] ; then
  echo "$0:  $IWCOMMAND essid \"$ESSID\"" | $LOGGER
  $IWCOMMAND essid "$ESSID"
fi
# The iwpriv can set one private IOCTL at the time, so if the $IWPRIV
# variable contains multiple pipe ('|') separated settings, we split them here:
# WARNING: if your iwpriv commands contain a WEP/WPA key, these can be logged
# in /var/log/messages!
if [ -n "$IWPRIV" ] ; then
  echo "${IWPRIV}|" | \
  while read -d '|' iwi; do
    if [ -n "$iwi" ]; then
      echo "$0:  $IWPRIVCMD $iwi" | $LOGGER
      $IWPRIVCMD $iwi
    fi
  done
fi

##################
# WPA_SUPPLICANT #
##################

# Support for WPA (wireless protected access) is provided by wpa_supplicant
# for those drivers that support it (and it looks like wpa_supplicant is
# the future for WPA support in Linux anyway)
if [ "$WPA" = "wpa_supplicant" ] || [ "$WPA" = "wpaxsupplicant" ] && [ -x ${SUPPATH}/wpa_supplicant ]; then
	# Interface down, so wpa_supplicant can associate with the AP
	$IFCOMMAND down
	#WPACONF=${WPACONF:-/etc/wpa_supplicant.conf}
	WPA_OPTIONS=""
	[ -n "$WPADRIVER" ] && WPA_OPTIONS="-D${WPADRIVER}" # specify the driver
	[ "$WPA" = "wpaxsupplicant" ] && WPA_OPTIONS="${WPA_OPTIONS} -e" # Use external xsupplicant (disables the internal supplicant)

	# We leave a running wpa_supplicant process in peace:
	if pgrep --full "bin/wpa_supplicant.* -i${INTERFACE}" >/dev/null ; then
	  echo "$0:  wpa_supplicant found running already" | $LOGGER
	else
	  echo "$0:  wpa_supplicant -B -c${WPACONF} ${WPA_OPTIONS} -i$INTERFACE" | $LOGGER
	  ${SUPPATH}/wpa_supplicant -B -c${WPACONF} ${WPA_OPTIONS} -i$INTERFACE
	fi

	# Buy wpa_supplicant some time to authenticate before bringing the
	# interface back up... but we don't wait forever:
	# You can increase this value in rc.inet1.conf (WLAN_WPAWAIT) or rc.wireless.conf (WPAWAIT)
        # if your card takes longer to associate:
	WPAWAIT=${WPAWAIT:-10}
	wi=0
	while [ $wi -lt $WPAWAIT ]; do
	  wi=$(($wi+1)); sleep 1
	  if (grep -q "^ctrl_interface=" ${WPACONF}); then
	    if (LC_ALL=C ${SUPPATH}/wpa_cli -i$INTERFACE status | grep -q "^wpa_state=COMPLETED"); then break; fi
	  else
	    if (LC_ALL=C ${IWCOMMAND} | grep -Eq "Encryption key:....-"); then break; fi
	  fi
	done
	if [ $wi -eq $WPAWAIT ]; then
	  echo "$0:  WPA authentication did not complete, try running '/etc/rc.d/rc.inet1 ${INTERFACE}_start' in a few seconds." | $LOGGER
	fi
	# Bring interface up to avoid 'not ready' errors when calling iwconfig
        # Update 09/Mar/21: No point bringing it up here to be taken down at exit.
	# $IFCOMMAND up
	# sleep 3
else
	# ESSID need to be last: most devices re-perform the scanning/discovery
	# when this is set, and things like encryption keys had better be
	# defined if we want to discover the right set of APs/nodes.
	# NOTE: when automatic association does not work, but you manage to get
	# an IP address by manually setting the ESSID and then calling dhcpcd,
	# then the cause might be the incorrect definition of your ESSID="bla"
	# parameter in rc.wireless.conf.
	# Debug your wireless problems by running 'iwevent' while the card
	# is being configured.
	if [ -n "$ESSID" ] ; then
	  echo "$0:  $IWCOMMAND essid \"$ESSID\"" | $LOGGER
	  $IWCOMMAND essid "$ESSID"
	fi
fi
$IFCOMMAND down
sleep 3