| 1 |
# Copyright 2004-2007 Gentoo Foundation |
| 2 |
# Distributed under the terms of the GNU General Public License v2 |
| 3 |
# Contributed by Roy Marples (uberlord@gentoo.org) |
| 4 |
# Many thanks to all the people in the Gentoo forums for their ideas and |
| 5 |
# motivation for me to make this and keep on improving it |
| 6 |
|
| 7 |
# Fix any potential localisation problems |
| 8 |
# Note that LC_ALL trumps LC_anything_else according to locale(7) |
| 9 |
iwconfig() { |
| 10 |
LC_ALL=C /sbin/iwconfig "$@" |
| 11 |
} |
| 12 |
iwgetid() { |
| 13 |
LC_ALL=C /sbin/iwgetid "$@" |
| 14 |
} |
| 15 |
iwlist() { |
| 16 |
LC_ALL=C /sbin/iwlist "$@" |
| 17 |
} |
| 18 |
iwpriv() { |
| 19 |
LC_ALL=C /sbin/iwpriv "$@" |
| 20 |
} |
| 21 |
|
| 22 |
# void iwconfig_depend(void) |
| 23 |
# |
| 24 |
# Sets up the dependancies for the module |
| 25 |
iwconfig_depend() { |
| 26 |
after plug |
| 27 |
before interface |
| 28 |
provide wireless |
| 29 |
functions interface_up interface_down interface_exists |
| 30 |
} |
| 31 |
|
| 32 |
# void iwconfig_expose(void) |
| 33 |
# |
| 34 |
# Expose variables that can be configured |
| 35 |
iwconfig_expose() { |
| 36 |
variables essid mode associate_timeout sleep_scan preferred_aps blacklist_aps |
| 37 |
} |
| 38 |
|
| 39 |
# bool iwconfig_check_installed(void) |
| 40 |
# |
| 41 |
# Returns 1 if wireless-tools is installed, otherwise 0 |
| 42 |
iwconfig_check_installed() { |
| 43 |
local report=${1:-false} |
| 44 |
[[ -x /sbin/iwconfig ]] && return 0 |
| 45 |
${report} && eerror "For Wireless (802.11) support, emerge net-wireless/wireless-tools" |
| 46 |
|
| 47 |
if [[ ! -e /proc/net/wireless ]]; then |
| 48 |
installed="1" |
| 49 |
if ${report} ; then |
| 50 |
eerror "iwconfig requires wireless support" |
| 51 |
eerror "(CONFIG_NET_WIRELESS=y) enabled in the kernel" |
| 52 |
fi |
| 53 |
fi |
| 54 |
|
| 55 |
return 1 |
| 56 |
} |
| 57 |
|
| 58 |
# bool iwconfig_exists(char *interface) |
| 59 |
# |
| 60 |
# Checks to see if wireless extensions are enabled on the interface |
| 61 |
iwconfig_exists() { |
| 62 |
# Support new sysfs layout |
| 63 |
[[ -L /sys/class/net/$1/wiphy || -d /sys/class/net/$1/wireless ]] \ |
| 64 |
&& return 0 |
| 65 |
|
| 66 |
[[ ! -e /proc/net/wireless ]] && return 1 |
| 67 |
grep -q "^[ \t]*$1:" /proc/net/wireless |
| 68 |
} |
| 69 |
|
| 70 |
# char* iwconfig_get_wep_status(char *interface) |
| 71 |
# |
| 72 |
# Echos a string showing whether WEP is enabled or disabled |
| 73 |
# for the given interface |
| 74 |
iwconfig_get_wep_status() { |
| 75 |
local mode= status="disabled" |
| 76 |
|
| 77 |
if iwconfig "$1" | grep -qE "^ +Encryption key:[*0-9,A-F]" ; then |
| 78 |
status="enabled" |
| 79 |
mode=$(iwconfig "$1" | sed -n -e 's/^.*Security mode:\(.*[^ ]\).*/\1/p') |
| 80 |
[[ -n ${mode} ]] && mode=" - ${mode}" |
| 81 |
fi |
| 82 |
|
| 83 |
echo "(WEP ${status}${mode})" |
| 84 |
} |
| 85 |
|
| 86 |
# char* iwconfig_get_essid(char *iface) |
| 87 |
# |
| 88 |
# Gets the current ESSID of the iface |
| 89 |
iwconfig_get_essid() { |
| 90 |
local i= essid= |
| 91 |
|
| 92 |
for (( i=0; i<5; i++ )); do |
| 93 |
essid=$( iwgetid --raw "$1" ) |
| 94 |
if [[ -n ${essid} ]] ; then |
| 95 |
echo "${essid}" |
| 96 |
return 0 |
| 97 |
fi |
| 98 |
sleep 1 |
| 99 |
done |
| 100 |
|
| 101 |
return 1 |
| 102 |
} |
| 103 |
|
| 104 |
# char* iwconfig_get_ap_mac_address(char *interface) |
| 105 |
# |
| 106 |
# Returns the MAC address of the Access Point |
| 107 |
# the interface is connected to |
| 108 |
iwconfig_get_ap_mac_address() { |
| 109 |
iwgetid --raw --ap "$1" |
| 110 |
} |
| 111 |
|
| 112 |
# char* iwconfig_get_mode(char *interface) |
| 113 |
# |
| 114 |
# Returns the wireless mode in lower case |
| 115 |
iwconfig_get_mode() { |
| 116 |
iwgetid --mode "$1" | sed -n -e 's/^.*Mode:\(.*\)/\L\1/p' |
| 117 |
} |
| 118 |
|
| 119 |
iwconfig_set_mode() { |
| 120 |
local iface="$1" mode="$2" |
| 121 |
[[ ${mode} == $(iwconfig_get_mode "${iface}") ]] && return 0 |
| 122 |
|
| 123 |
# Devicescape stack requires the interface to be down |
| 124 |
interface_down "${iface}" |
| 125 |
if ! iwconfig "${iface}" mode "${mode}" ; then |
| 126 |
eerror "${iface} does not support setting the mode to \"${mode}\"" |
| 127 |
return 1 |
| 128 |
fi |
| 129 |
interface_up "${iface}" |
| 130 |
} |
| 131 |
|
| 132 |
# char* iwconfig_get_type(char *interface) |
| 133 |
# |
| 134 |
# Returns the type of interface - the IEEE part |
| 135 |
iwconfig_get_type() { |
| 136 |
iwconfig "$1" | sed -n -e 's/^'"$1"' *\([^ ]* [^ ]*\).*/\1/p' |
| 137 |
} |
| 138 |
|
| 139 |
# void iwconfig_report(char *interface) |
| 140 |
# |
| 141 |
# Output how our wireless interface has been configured |
| 142 |
iwconfig_report() { |
| 143 |
local iface="$1" essid= mac= m="connected to" |
| 144 |
|
| 145 |
essid=$(iwconfig_get_essid "${iface}") |
| 146 |
|
| 147 |
local wep_status=$(iwconfig_get_wep_status "${iface}") |
| 148 |
local channel=$(iwgetid --raw --channel "${iface}") |
| 149 |
[[ -n ${channel} ]] && channel="on channel ${channel} " |
| 150 |
|
| 151 |
essid="${essid//\\\\/\\\\}" |
| 152 |
local mode=$(iwconfig_get_mode "${iface}") |
| 153 |
if [[ ${mode} == "master" ]]; then |
| 154 |
m="configured as" |
| 155 |
else |
| 156 |
mac=$(iwconfig_get_ap_mac_address "${iface}") |
| 157 |
[[ -n ${mac} ]] && mac=" at ${mac}" |
| 158 |
fi |
| 159 |
|
| 160 |
eindent |
| 161 |
einfo "${iface} ${m} ESSID \"${essid}\"${mac}" |
| 162 |
einfo "in ${mode} mode ${channel}${wep_status}" |
| 163 |
eoutdent |
| 164 |
} |
| 165 |
|
| 166 |
# char* iwconfig_get_wep_key(char *mac_address) |
| 167 |
# |
| 168 |
# Returns the configured WEP key for the given mac address |
| 169 |
# or the given ESSID. The mac address setting takes precendence |
| 170 |
iwconfig_get_wep_key() { |
| 171 |
local mac="$1" key= |
| 172 |
key="mac_key_${mac//:/}" |
| 173 |
[[ -z ${!key} ]] && key="key_${ESSIDVAR}" |
| 174 |
echo "${!key:-off}" |
| 175 |
} |
| 176 |
|
| 177 |
# void iwconfig_user_config(char *iface, char *ifvar) |
| 178 |
# |
| 179 |
# Applies the user configuration to the interface |
| 180 |
iwconfig_user_config() { |
| 181 |
local iface="$1" conf= aconf= ifvar="$2" |
| 182 |
[[ -z ${ifvar} ]] && ifvar=$(bash_variable "$1") |
| 183 |
|
| 184 |
# Apply the user configuration |
| 185 |
conf="iwconfig_${ifvar}" |
| 186 |
if [[ -n ${!conf} ]]; then |
| 187 |
aconf=( "${!conf}" ) |
| 188 |
for conf in "${aconf[@]}" ; do |
| 189 |
if ! iwconfig "${iface}" ${conf} ; then |
| 190 |
ewarn "${iface} does not support the following configuration commands" |
| 191 |
ewarn " ${conf}" |
| 192 |
fi |
| 193 |
done |
| 194 |
fi |
| 195 |
|
| 196 |
conf="iwpriv_${ifvar}[@]" |
| 197 |
if [[ -n ${!conf} ]]; then |
| 198 |
aconf=( "${!conf}" ) |
| 199 |
for conf in "${aconf[@]}" ; do |
| 200 |
if ! iwpriv "${iface}" ${conf} ; then |
| 201 |
ewarn "${iface} does not support the following private ioctls" |
| 202 |
ewarn " ${conf}" |
| 203 |
fi |
| 204 |
done |
| 205 |
fi |
| 206 |
} |
| 207 |
|
| 208 |
# bool iwconfig_setup_specific(char *iface) |
| 209 |
# |
| 210 |
# Sets up our wireless interface to operate in ad-hoc or master mode |
| 211 |
iwconfig_setup_specific() { |
| 212 |
local iface="$1" mode="$2" channel= key= dessid= |
| 213 |
local ifvar=$(bash_variable "$1") |
| 214 |
|
| 215 |
if [[ -z ${ESSID} ]]; then |
| 216 |
eerror "${iface} requires an ESSID to be set to operate in ${mode} mode" |
| 217 |
eerror "adjust the essid_${iface} setting in /etc/conf.d/wireless" |
| 218 |
return 1 |
| 219 |
fi |
| 220 |
dessid="${ESSID//\\\\/\\\\}" |
| 221 |
ESSIDVAR=$(bash_variable "${ESSID}") |
| 222 |
key=$(iwconfig_get_wep_key) |
| 223 |
|
| 224 |
iwconfig_set_mode "${iface}" "${mode}" |
| 225 |
|
| 226 |
# Now set the key |
| 227 |
if ! eval iwconfig "${iface}" key "${key}" ; then |
| 228 |
if [[ ${key} != "off" ]]; then |
| 229 |
ewarn "${iface} does not support setting keys" |
| 230 |
ewarn "or the parameter \"mac_key_${ESSIDVAR}\" or \"key_${ESSIDVAR}\" is incorrect" |
| 231 |
fi |
| 232 |
fi |
| 233 |
|
| 234 |
# Then set the ESSID |
| 235 |
if ! eval iwconfig "${iface}" essid "${ESSID}" ; then |
| 236 |
eerror "${iface} does not support setting ESSID to \"${dessid}\"" |
| 237 |
return 1 |
| 238 |
fi |
| 239 |
|
| 240 |
channel="channel_${ifvar}" |
| 241 |
# We default the channel to 3 |
| 242 |
if ! iwconfig "${iface}" channel "${!channel:-3}" ; then |
| 243 |
ewarn "${iface} does not support setting the channel to \"${!channel:-3}\"" |
| 244 |
return 1 |
| 245 |
fi |
| 246 |
|
| 247 |
# Finally apply the user Config |
| 248 |
iwconfig_user_config "${iface}" "${ESSIDVAR}" |
| 249 |
|
| 250 |
iwconfig_report "${iface}" |
| 251 |
|
| 252 |
return 0 |
| 253 |
} |
| 254 |
|
| 255 |
# bool iwconfig_associate_mac(char *iface) |
| 256 |
# |
| 257 |
# Returns true if the AP MAC address is valid or not |
| 258 |
iwconfig_associate_mac() { |
| 259 |
# Checks if a MAC address has been assigned |
| 260 |
local mac=$(iwconfig_get_ap_mac_address "$1") i= |
| 261 |
local -a invalid_macs=( |
| 262 |
"00:00:00:00:00:00" |
| 263 |
"44:44:44:44:44:44" |
| 264 |
"FF:00:00:00:00:00" |
| 265 |
"FF:FF:FF:FF:FF:FF" |
| 266 |
) |
| 267 |
|
| 268 |
[[ -z ${mac} ]] && return 1 |
| 269 |
for i in "${invalid_macs[@]}"; do |
| 270 |
[[ ${mac} == "${i}" ]] && return 1 |
| 271 |
done |
| 272 |
return 0 |
| 273 |
} |
| 274 |
|
| 275 |
# bool iwconfig_associate_quality(char *iface) |
| 276 |
# |
| 277 |
# Returns true if the link quality is not 0 or 0. |
| 278 |
iwconfig_associate_quality() { |
| 279 |
local quality=$( \ |
| 280 |
sed -n -e 's/^.*'"$1"': *[0-9]* *\([0-9]*\).*/\1/p' \ |
| 281 |
/proc/net/wireless |
| 282 |
) |
| 283 |
[[ ${quality} != "0" ]] |
| 284 |
return "$?" |
| 285 |
} |
| 286 |
|
| 287 |
# bool iwconfig_test_associated(char *iface) |
| 288 |
# |
| 289 |
# Returns true if the interface has associated with an Access Point |
| 290 |
iwconfig_test_associated() { |
| 291 |
local iface="$1" ttype= ifvar=$(bash_variable "$1") x= |
| 292 |
# Some drivers don't set MAC to a bogus value when assocation is lost/fails |
| 293 |
# whereas they do set link quality to 0 |
| 294 |
|
| 295 |
# Use sysfs if we can |
| 296 |
if [[ -e /sys/class/net/${iface}/carrier ]] ; then |
| 297 |
[[ $(</sys/class/net/"${iface}"/carrier) == "1" ]] |
| 298 |
return $? |
| 299 |
fi |
| 300 |
|
| 301 |
x="associate_test_${ifvar}" |
| 302 |
ttype=$(echo "${!x:-mac}" | tr '[:upper:]' '[:lower:]') |
| 303 |
if [[ ${ttype} != "mac" && ${ttype} != "quality" && ${ttype} != "all" ]]; then |
| 304 |
ewarn " associate_test_${iface} is not set to mac, quality or all" |
| 305 |
ewarn " defaulting to \"mac\"" |
| 306 |
test="mac" |
| 307 |
fi |
| 308 |
|
| 309 |
case "${ttype}" in |
| 310 |
mac) iwconfig_associate_mac "${iface}" && return 0 ;; |
| 311 |
quality) iwconfig_associate_quality "${iface}" && return 0 ;; |
| 312 |
all) iwconfig_associate_mac "${iface}" \ |
| 313 |
&& iwconfig_associate_quality "${iface}" && return 0 ;; |
| 314 |
esac |
| 315 |
|
| 316 |
return 1 |
| 317 |
} |
| 318 |
|
| 319 |
# bool iwconfig_wait_for_association(char *iface) |
| 320 |
# |
| 321 |
# Waits for a configured ammount of time until |
| 322 |
# we are assocaited with an Access Point |
| 323 |
iwconfig_wait_for_association() { |
| 324 |
local iface="$1" i=0 timeout= ifvar=$(bash_variable "$1") |
| 325 |
timeout="associate_timeout_${ifvar}" |
| 326 |
[[ -z ${!timeout} ]] && timeout="sleep_associate_${ifvar}" |
| 327 |
timeout="${!timeout:-10}" |
| 328 |
|
| 329 |
[[ ${timeout} == "0" ]] \ |
| 330 |
&& vewarn "WARNING: infinite timeout set for association on ${iface}" |
| 331 |
|
| 332 |
while true; do |
| 333 |
iwconfig_test_associated "${iface}" && return 0 |
| 334 |
sleep 1 |
| 335 |
[[ ${timeout} == "0" ]] && continue |
| 336 |
(( i++ )) |
| 337 |
[[ ${i} == "${timeout}" || ${i} -gt ${timeout} ]] && break |
| 338 |
done |
| 339 |
return 1 |
| 340 |
} |
| 341 |
|
| 342 |
# bool iwconfig_associate(char *interface, char *mac_address, char *wep_required) |
| 343 |
# |
| 344 |
# Tries to associate the interface with an Access Point |
| 345 |
# If we scanned the Access Point we know if we need WEP to associate or not |
| 346 |
# and if we have a WEP key for the ESSID or not |
| 347 |
# so we can fail gracefully without even trying to connect |
| 348 |
iwconfig_associate() { |
| 349 |
local iface="$1" mode="${2:-managed}" |
| 350 |
local mac="$3" wep_required="$4" freq="$5" chan="$6" w="(WEP Disabled)" |
| 351 |
local dessid="${ESSID//\\\\/\\\\}" key= |
| 352 |
|
| 353 |
iwconfig_set_mode "${iface}" "${mode}" |
| 354 |
|
| 355 |
if [[ ${ESSID} == "any" ]]; then |
| 356 |
iwconfig "${iface}" ap any 2>/dev/null |
| 357 |
dessid="any" |
| 358 |
unset ESSIDVAR |
| 359 |
else |
| 360 |
ESSIDVAR=$(bash_variable "${ESSID}") |
| 361 |
key=$(iwconfig_get_wep_key "${mac}") |
| 362 |
if [[ ${wep_required} == "on" && ${key} == "off" ]]; then |
| 363 |
ewarn "WEP key is not set for \"${dessid}\" - not connecting" |
| 364 |
return 1 |
| 365 |
fi |
| 366 |
if [[ ${wep_required} == "off" && ${key} != "off" ]]; then |
| 367 |
key="off" |
| 368 |
ewarn "\"${dessid}\" is not WEP enabled - ignoring setting" |
| 369 |
fi |
| 370 |
|
| 371 |
if ! eval iwconfig "${iface}" key "${key}" ; then |
| 372 |
if [[ ${key} != "off" ]]; then |
| 373 |
ewarn "${iface} does not support setting keys" |
| 374 |
ewarn "or the parameter \"mac_key_${ESSIDVAR}\" or \"key_${ESSIDVAR}\" is incorrect" |
| 375 |
return 1 |
| 376 |
fi |
| 377 |
fi |
| 378 |
[[ ${key} != "off" ]] && w=$(iwconfig_get_wep_status "${iface}") |
| 379 |
fi |
| 380 |
|
| 381 |
if ! eval iwconfig "${iface}" essid "${ESSID}" ; then |
| 382 |
if [[ ${ESSID} != "any" ]]; then |
| 383 |
ewarn "${iface} does not support setting ESSID to \"${dessid}\"" |
| 384 |
fi |
| 385 |
fi |
| 386 |
|
| 387 |
# Only use channel or frequency |
| 388 |
if [[ -n ${chan} ]] ; then |
| 389 |
iwconfig "${iface}" channel "${chan}" |
| 390 |
elif [[ -n ${freq} ]] ; then |
| 391 |
iwconfig "${iface}" freq "${freq}" |
| 392 |
fi |
| 393 |
[[ -n ${mac} ]] && iwconfig "${iface}" ap "${mac}" |
| 394 |
|
| 395 |
# Finally apply the user Config |
| 396 |
iwconfig_user_config "${iface}" "${ESSIDVAR}" |
| 397 |
|
| 398 |
vebegin "Connecting to \"${dessid}\" in ${mode} mode ${w}" |
| 399 |
|
| 400 |
if [[ ${ESSID} != "any" ]] && is_function preassociate ; then |
| 401 |
veinfo "Running preassociate function" |
| 402 |
eindent |
| 403 |
( preassociate "${iface}" ) |
| 404 |
e="$?" |
| 405 |
eoutdent |
| 406 |
if [[ ${e} != 0 ]]; then |
| 407 |
veend 1 "preassociate \"${dessid}\" on ${iface} failed" |
| 408 |
return 1 |
| 409 |
fi |
| 410 |
fi |
| 411 |
|
| 412 |
if ! iwconfig_wait_for_association "${iface}" ; then |
| 413 |
veend 1 |
| 414 |
return 1 |
| 415 |
fi |
| 416 |
veend 0 |
| 417 |
|
| 418 |
if [[ ${ESSID} == "any" ]]; then |
| 419 |
ESSID=$(iwconfig_get_essid "${iface}") |
| 420 |
iwconfig_associate "${iface}" |
| 421 |
return $? |
| 422 |
fi |
| 423 |
|
| 424 |
iwconfig_report "${iface}" |
| 425 |
|
| 426 |
if is_function postassociate ; then |
| 427 |
veinfo "Running postassociate function" |
| 428 |
eindent |
| 429 |
( postassociate "${iface}" ) |
| 430 |
eoutdent |
| 431 |
fi |
| 432 |
|
| 433 |
return 0 |
| 434 |
} |
| 435 |
|
| 436 |
# bool iwconfig_scan(char *iface) |
| 437 |
# |
| 438 |
# Fills 3 arrays with information from a wireless scan |
| 439 |
iwconfig_scan() { |
| 440 |
local iface="$1" mode= x= ifvar=$(bash_variable "$1") |
| 441 |
|
| 442 |
# Set any private driver ioctls needed |
| 443 |
x="iwpriv_scan_pre_${ifvar}" |
| 444 |
if [[ -n ${!x} ]]; then |
| 445 |
if ! eval iwpriv "${iface}" "${!x}" ; then |
| 446 |
ewarn "${iface} does not support the following private ioctls" \ |
| 447 |
ewarn " ${!x}" |
| 448 |
fi |
| 449 |
fi |
| 450 |
|
| 451 |
veinfo "Scanning for access points" |
| 452 |
|
| 453 |
# Sleep if required |
| 454 |
x="sleep_scan_${ifvar}" |
| 455 |
[[ -z ${!x} || ${!x} -gt 0 ]] && sleep "${!x:-2}" |
| 456 |
|
| 457 |
local error=true i=-1 line= |
| 458 |
local -a mac=() essid=() enc=() qual=() mode=() freq=() chan=() |
| 459 |
|
| 460 |
while read line; do |
| 461 |
error=false |
| 462 |
case "${line}" in |
| 463 |
*Address:*) |
| 464 |
(( i++ )) |
| 465 |
mac[i]=$(echo "${line#*: }" | tr '[:lower:]' '[:upper:]') |
| 466 |
qual[i]=0 |
| 467 |
;; |
| 468 |
*ESSID:*) |
| 469 |
essid[i]="${line#*\"}" |
| 470 |
essid[i]="${essid[i]%*\"}" |
| 471 |
;; |
| 472 |
*Mode:*) |
| 473 |
mode[i]=$(echo "${line#*:}" | tr '[:upper:]' '[:lower:]') |
| 474 |
[[ ${mode[i]} == "master" ]] && mode[i]="managed" |
| 475 |
;; |
| 476 |
*'Encryption key:'*) |
| 477 |
enc[i]="${line#*:}" |
| 478 |
;; |
| 479 |
*Frequency:*) |
| 480 |
freq[i]="${line#*:}" |
| 481 |
x="${freq[i]#* }" |
| 482 |
freq[i]="${freq[i]%% *}${x:0:1}" |
| 483 |
;; |
| 484 |
*Channel:*) |
| 485 |
chan[i]="${line#*:}" |
| 486 |
chan[i]="${chan[i]%% *}" |
| 487 |
;; |
| 488 |
*Quality*) |
| 489 |
qual[i]="${line#*:}" |
| 490 |
qual[i]="${qual[i]%/*}" |
| 491 |
qual[i]="${qual[i]//[![:digit:]]/}" |
| 492 |
qual[i]="${qual[i]:-0}" |
| 493 |
;; |
| 494 |
esac |
| 495 |
done < <(iwlist "${iface}" scan 2>/dev/null) |
| 496 |
|
| 497 |
if ${error}; then |
| 498 |
ewarn "${iface} does not support scanning" |
| 499 |
x="adhoc_essid_${ifvar}" |
| 500 |
[[ -n ${!x} ]] && return 0 |
| 501 |
if [[ -n ${preferred_aps} ]]; then |
| 502 |
[[ ${associate_order} == "forcepreferred" \ |
| 503 |
|| ${associate_order} == "forcepreferredonly" ]] && return 0 |
| 504 |
fi |
| 505 |
eerror "You either need to set a preferred_aps list in /etc/conf.d/wireless" |
| 506 |
eerror " preferred_aps=( \"ESSID1\" \"ESSID2\" )" |
| 507 |
eerror " and set associate_order_${iface}=\"forcepreferred\"" |
| 508 |
eerror " or set associate_order_${iface}=\"forcepreferredonly\"" |
| 509 |
eerror "or hardcode the ESSID to \"any\" and let the driver find an Access Point" |
| 510 |
eerror " essid_${iface}=\"any\"" |
| 511 |
eerror "or configure defaulting to Ad-Hoc when Managed fails" |
| 512 |
eerror " adhoc_essid_${iface}=\"WLAN\"" |
| 513 |
eerror "or hardcode the ESSID against the interface (not recommended)" |
| 514 |
eerror " essid_${iface}=\"ESSID\"" |
| 515 |
return 1 |
| 516 |
fi |
| 517 |
|
| 518 |
# We may need to unset the previous private driver ioctls |
| 519 |
x="iwpriv_scan_post_${ifvar}" |
| 520 |
if [[ -n ${!x} ]]; then |
| 521 |
if ! eval iwpriv "${iface}" "${!x}" ; then |
| 522 |
ewarn "${iface} does not support the following private ioctls" \ |
| 523 |
ewarn " ${!x}" |
| 524 |
fi |
| 525 |
fi |
| 526 |
|
| 527 |
# Strip any duplicates |
| 528 |
local i= j= x="${#mac[@]}" y= |
| 529 |
for (( i=0; i<x-1; i++ )) ; do |
| 530 |
[[ -z ${mac[i]} ]] && continue |
| 531 |
for (( j=i+1; j<x; j++)) ; do |
| 532 |
if [[ ${mac[i]} == "${mac[j]}" ]] ; then |
| 533 |
if [[ ${qual[i]} -gt ${qual[j]} ]] ; then |
| 534 |
y="${j}" |
| 535 |
else |
| 536 |
y="${j}" |
| 537 |
fi |
| 538 |
unset mac[y] |
| 539 |
unset qual[y] |
| 540 |
unset essid[y] |
| 541 |
unset mode[y] |
| 542 |
unset enc[y] |
| 543 |
unset freq[y] |
| 544 |
unset chan[y] |
| 545 |
fi |
| 546 |
done |
| 547 |
done |
| 548 |
mac=( "${mac[@]}" ) |
| 549 |
qual=( "${qual[@]}" ) |
| 550 |
essid=( "${essid[@]}" ) |
| 551 |
mode=( "${mode[@]}" ) |
| 552 |
enc=( "${enc[@]}" ) |
| 553 |
freq=( "${freq[@]}" ) |
| 554 |
chan=( "${chan[@]}" ) |
| 555 |
|
| 556 |
for (( i=0; i<${#mac[@]}; i++ )); do |
| 557 |
# Don't like ad-hoc nodes by default |
| 558 |
[[ ${mode[i]} == "ad-hoc" ]] && (( qual[i]-=10000 )) |
| 559 |
sortline="${sortline}${qual[i]} ${i}\n" |
| 560 |
done |
| 561 |
sortline=( $(echo -e "${sortline}" | sort -nr) ) |
| 562 |
|
| 563 |
for (( i=0; i<${#mac[@]}; i++ )); do |
| 564 |
(( x=(i * 2) + 1 )) |
| 565 |
mac_APs[i]="${mac[${sortline[x]}]}" |
| 566 |
essid_APs[i]="${essid[${sortline[x]}]}" |
| 567 |
mode_APs[i]="${mode[${sortline[x]}]}" |
| 568 |
enc_APs[i]="${enc[${sortline[x]}]}" |
| 569 |
freq_APs[i]="${freq[${sortline[x]}]}" |
| 570 |
chan_APs[i]="${chan[${sortline[x]}]}" |
| 571 |
done |
| 572 |
|
| 573 |
return 0 |
| 574 |
} |
| 575 |
|
| 576 |
# void iwconfig_scan_report(void) |
| 577 |
# |
| 578 |
# Report the results of the scan and re-map any ESSIDs if they |
| 579 |
# have been configured for the MAC address found |
| 580 |
iwconfig_scan_report() { |
| 581 |
local i= k= m= remove= |
| 582 |
local -a u=() |
| 583 |
|
| 584 |
[[ -z ${mac_APs} ]] && ewarn " no access points found" |
| 585 |
|
| 586 |
# We need to do the for loop like this so we can |
| 587 |
# dynamically remove from the array |
| 588 |
eindent |
| 589 |
for ((i=0; i<${#mac_APs[@]}; i++)); do |
| 590 |
k="(${mode_APs[i]}" |
| 591 |
[[ ${enc_APs[i]} != "off" ]] && k="${k}, encrypted" |
| 592 |
k="${k})" |
| 593 |
|
| 594 |
if [[ -z ${essid_APs[i]} ]]; then |
| 595 |
veinfo "Found ${mac_APs[i]} ${k}" |
| 596 |
else |
| 597 |
veinfo "Found \"${essid_APs[i]//\\\\/\\\\}\" at ${mac_APs[i]} ${k}" |
| 598 |
fi |
| 599 |
|
| 600 |
eindent |
| 601 |
|
| 602 |
m="mac_essid_${mac_APs[i]//:/}" |
| 603 |
if [[ -n ${!m} ]]; then |
| 604 |
essid_APs[i]="${!m}" |
| 605 |
veinfo "mapping to \"${!m//\\\\/\\\\}\"" |
| 606 |
fi |
| 607 |
|
| 608 |
remove=false |
| 609 |
# If we don't know the essid then we cannot connect to them |
| 610 |
# so we remove them from our array |
| 611 |
if [[ -z ${essid_APs[i]} ]]; then |
| 612 |
remove=true |
| 613 |
else |
| 614 |
for k in "${blacklist_aps[@]}"; do |
| 615 |
if [[ ${k} == "${essid_APs[i]}" ]]; then |
| 616 |
vewarn "\"${k//\\\\/\\\\}\" has been blacklisted - not connecting" |
| 617 |
remove=true |
| 618 |
break |
| 619 |
fi |
| 620 |
done |
| 621 |
fi |
| 622 |
|
| 623 |
eoutdent |
| 624 |
|
| 625 |
${remove} && u=( "${u[@]}" "${i}" ) |
| 626 |
done |
| 627 |
|
| 628 |
eoutdent |
| 629 |
|
| 630 |
# Now we remove any duplicates |
| 631 |
for ((i=0; i < ${#essid_APs[@]} - 1; i++)); do |
| 632 |
for ((j=${i} + 1; j <${#essid_APs[@]}; j++)); do |
| 633 |
[[ ${essid_APs[i]} == "${essid_APs[j]}" ]] && u=( "${u[@]}" "${j}" ) |
| 634 |
done |
| 635 |
done |
| 636 |
|
| 637 |
for i in ${u[@]}; do |
| 638 |
unset essid_APs[i] |
| 639 |
unset mode_APs[i] |
| 640 |
unset mac_APs[i] |
| 641 |
unset enc_APs[i] |
| 642 |
unset freq_APs[i] |
| 643 |
unset chan_APs[i] |
| 644 |
done |
| 645 |
|
| 646 |
# We need to squash our arrays so indexes work again |
| 647 |
essid_APs=( "${essid_APs[@]}" ) |
| 648 |
mode_APs=( "${mode_APs[@]}" ) |
| 649 |
mac_APs=( "${mac_APs[@]}" ) |
| 650 |
enc_APs=( "${enc_APs[@]}" ) |
| 651 |
freq_APs=( "${freq_APs[@]}" ) |
| 652 |
chan_APs=( "${chan_APs[@]}" ) |
| 653 |
} |
| 654 |
|
| 655 |
# bool iwconfig_force_preferred(char *iface) |
| 656 |
# |
| 657 |
# Forces the preferred_aps list to associate in order |
| 658 |
# but only if they were not picked up by our scan |
| 659 |
iwconfig_force_preferred() { |
| 660 |
local iface=$1 essid= i= |
| 661 |
|
| 662 |
[[ -z ${preferred_aps} ]] && return 1 |
| 663 |
|
| 664 |
ewarn "Trying to force preferred in case they are hidden" |
| 665 |
for essid in "${preferred_aps[@]}"; do |
| 666 |
local found_AP=false |
| 667 |
for ((i = 0; i < ${#mac_APs[@]}; i++)); do |
| 668 |
if [[ ${essid} == "${essid_APs[i]}" ]]; then |
| 669 |
found_AP=true |
| 670 |
break |
| 671 |
fi |
| 672 |
done |
| 673 |
if ! ${found_AP} ; then |
| 674 |
ESSID="${essid}" |
| 675 |
iwconfig_associate "${iface}" && return 0 |
| 676 |
fi |
| 677 |
done |
| 678 |
|
| 679 |
ewarn "Failed to associate with any preferred access points on ${iface}" |
| 680 |
return 1 |
| 681 |
} |
| 682 |
|
| 683 |
# bool iwconfig_connect_preferred(char *iface) |
| 684 |
# |
| 685 |
# Connects to preferred_aps in order if they were picked up |
| 686 |
# by our scan |
| 687 |
iwconfig_connect_preferred() { |
| 688 |
local iface="$1" essid= i= |
| 689 |
|
| 690 |
for essid in "${preferred_aps[@]}"; do |
| 691 |
for ((i=0; i<${#essid_APs[@]}; i++)); do |
| 692 |
if [[ ${essid} == "${essid_APs[i]}" ]]; then |
| 693 |
ESSID="${essid}" |
| 694 |
iwconfig_associate "${iface}" "${mode_APs[i]}" "${mac_APs[i]}" \ |
| 695 |
"${enc_APs[i]}" "${freq_APs[i]}" "${chan_APs[i]}" && return 0 |
| 696 |
break |
| 697 |
fi |
| 698 |
done |
| 699 |
done |
| 700 |
|
| 701 |
return 1 |
| 702 |
} |
| 703 |
|
| 704 |
# bool iwconfig_connect_not_preferred(char *iface) |
| 705 |
# |
| 706 |
# Connects to any AP's found that are not in |
| 707 |
# our preferred list |
| 708 |
iwconfig_connect_not_preferred() { |
| 709 |
local iface=$1 i= ap= has_preferred= |
| 710 |
|
| 711 |
for ((i=0; i<${#mac_APs[@]}; i++)); do |
| 712 |
has_preferred=false |
| 713 |
for ap in "${preferred_aps[@]}"; do |
| 714 |
if [[ ${ap} == "${essid_APs[i]}" ]]; then |
| 715 |
has_preferred=true |
| 716 |
break |
| 717 |
fi |
| 718 |
done |
| 719 |
if ! ${has_preferred} ; then |
| 720 |
ESSID="${essid_APs[i]}" |
| 721 |
iwconfig_associate "${iface}" "${mode_APs[i]}" "${mac_APs[i]}" \ |
| 722 |
"${enc_APs[i]}" "${freq_APs[i]}" "${chan_APs[i]}" && return 0 |
| 723 |
fi |
| 724 |
done |
| 725 |
|
| 726 |
return 1 |
| 727 |
} |
| 728 |
|
| 729 |
# void iwconfig_defaults(char *iface) |
| 730 |
# |
| 731 |
# Apply some sane defaults to the wireless interface |
| 732 |
# incase the user already applied some changes |
| 733 |
iwconfig_defaults() { |
| 734 |
local iface="$1" |
| 735 |
|
| 736 |
# Set some defaults |
| 737 |
iwconfig "${iface}" txpower auto 2>/dev/null |
| 738 |
iwconfig "${iface}" rate auto 2>/dev/null |
| 739 |
iwconfig "${iface}" rts auto 2>/dev/null |
| 740 |
iwconfig "${iface}" frag auto 2>/dev/null |
| 741 |
|
| 742 |
# Release the AP forced |
| 743 |
# Must do ap and then essid otherwise scanning borks |
| 744 |
iwconfig "${iface}" ap off 2>/dev/null |
| 745 |
iwconfig "${iface}" essid off 2>/dev/null |
| 746 |
} |
| 747 |
|
| 748 |
# void iwconfig_strip_associated(char *iface) |
| 749 |
# |
| 750 |
# We check to see which ifaces have associated AP's except for the iface |
| 751 |
# given and remove those AP's from the scan list |
| 752 |
# We also remove from the preferred list |
| 753 |
iwconfig_strip_associated() { |
| 754 |
local iface="$1" e= a= j= |
| 755 |
local essid=$(iwconfig_get_essid "${iface}") |
| 756 |
local -a ifaces=( $( iwconfig 2>/dev/null | grep -o "^\w*" ) ) |
| 757 |
|
| 758 |
for i in "${ifaces[@]}"; do |
| 759 |
[[ ${i} == ${iface} ]] && continue |
| 760 |
interface_is_up "${i}" || continue |
| 761 |
iwconfig_test_associated "${i}" || continue |
| 762 |
e=$(iwconfig_get_essid "${i}") |
| 763 |
local -a u=() |
| 764 |
for ((j=0; j<${#mac_APs[@]}; j++)); do |
| 765 |
if [[ ${essid_APs[j]} == "${e}" ]]; then |
| 766 |
ewarn "${e} has already been associated with ${i}" |
| 767 |
unset essid_APs[j] |
| 768 |
unset mode_Aps[j] |
| 769 |
unset mac_APs[j] |
| 770 |
unset enc_APs[j] |
| 771 |
unset freq_APs[j] |
| 772 |
unset chan_APs[j] |
| 773 |
# We need to squash our arrays so that indexes work |
| 774 |
essid_APs=( "${essid_APs[@]}" ) |
| 775 |
mode_APs=( "${mode_APs[@]}" ) |
| 776 |
mac_APs=( "${mac_APs[@]}" ) |
| 777 |
enc_APs=( "${enc_APs[@]}" ) |
| 778 |
freq_APs=( "${freq_APs[@]}" ) |
| 779 |
chan_APs=( "${chan_APs[@]}" ) |
| 780 |
break |
| 781 |
fi |
| 782 |
done |
| 783 |
for ((j=0; j<${#preferred_aps[@]}; j++)); do |
| 784 |
if [[ ${preferred_aps[j]} == "${e}" ]]; then |
| 785 |
unset preferred_aps[j] |
| 786 |
preferred_aps=( "${preferred_aps[@]}" ) |
| 787 |
break |
| 788 |
fi |
| 789 |
done |
| 790 |
done |
| 791 |
} |
| 792 |
|
| 793 |
# bool iwconfig_configure(char *iface) |
| 794 |
# |
| 795 |
# The main startup code |
| 796 |
# First we bring the interface up, apply defaults, apply user configuration |
| 797 |
# Then we test to see if ad-hoc mode has been requested and branch if needed |
| 798 |
# Then we scan for access points and try to connect to them in a predetermined order |
| 799 |
# Once we're connected we show a report and then configure any interface |
| 800 |
# variables for the ESSID |
| 801 |
iwconfig_configure() { |
| 802 |
local iface="$1" e= x= ifvar=$(bash_variable "$1") |
| 803 |
local -a essid_APs=() mac_APs=() mode_APs=() |
| 804 |
local -a enc_APs=() freq_APs=() chan_APs=() |
| 805 |
|
| 806 |
ESSID="essid_${ifvar}" |
| 807 |
ESSID="${!ESSID}" |
| 808 |
|
| 809 |
# Setup ad-hoc mode? |
| 810 |
x="mode_${ifvar}" |
| 811 |
x=$(echo "${!x:-managed}" | tr '[:upper:]' '[:lower:]') |
| 812 |
if [[ ${x} == "ad-hoc" || ${x} == "master" ]]; then |
| 813 |
iwconfig_setup_specific "${iface}" "${x}" |
| 814 |
return $? |
| 815 |
fi |
| 816 |
|
| 817 |
if [[ ${x} != "managed" && ${x} != "auto" ]]; then |
| 818 |
eerror "Only managed, ad-hoc, master and auto modes are supported" |
| 819 |
return 1 |
| 820 |
fi |
| 821 |
|
| 822 |
# Has an ESSID been forced? |
| 823 |
if [[ -n ${ESSID} ]]; then |
| 824 |
iwconfig_set_mode "${iface}" "${x}" |
| 825 |
iwconfig_associate "${iface}" && return 0 |
| 826 |
[[ ${ESSID} == "any" ]] && iwconfig_force_preferred "${iface}" && return 0 |
| 827 |
|
| 828 |
ESSID="adhoc_essid_${ifvar}" |
| 829 |
ESSID="${!ESSID}" |
| 830 |
if [[ -n ${ESSID} ]]; then |
| 831 |
iwconfig_setup_specific "${iface}" ad-hoc |
| 832 |
return $? |
| 833 |
fi |
| 834 |
return 1 |
| 835 |
fi |
| 836 |
|
| 837 |
# Do we have a preferred Access Point list specific to the interface? |
| 838 |
x="preferred_aps_${ifvar}[@]" |
| 839 |
[[ -n ${!x} ]] && preferred_aps=( "${!x}" ) |
| 840 |
|
| 841 |
# Do we have a blacklist Access Point list specific to the interface? |
| 842 |
x="blacklist_aps_${ifvar}[@]" |
| 843 |
[[ -n ${!x} ]] && blacklist_aps=( "${!x}" ) |
| 844 |
|
| 845 |
# Are we forcing preferred only? |
| 846 |
x="associate_order_${ifvar}" |
| 847 |
[[ -n ${!x} ]] && associate_order="${!x}" |
| 848 |
associate_order=$(echo "${associate_order:-any}" \ |
| 849 |
| tr '[:upper:]' '[:lower:]') |
| 850 |
|
| 851 |
if [[ ${associate_order} == "forcepreferredonly" ]]; then |
| 852 |
iwconfig_force_preferred "${iface}" && return 0 |
| 853 |
else |
| 854 |
iwconfig_scan "${iface}" || return 1 |
| 855 |
iwconfig_scan_report |
| 856 |
|
| 857 |
# Strip AP's from the list that have already been associated with |
| 858 |
# other wireless cards in the system if requested |
| 859 |
x="unique_ap_${ifvar}" |
| 860 |
[[ -n ${!x} ]] && unique_ap="${!x}" |
| 861 |
unique_ap=$(echo "${unique_ap:-no}" | tr '[:upper:]' '[:lower:]') |
| 862 |
[[ ${unique_ap} != "no" ]] && iwconfig_strip_associated "${iface}" |
| 863 |
|
| 864 |
iwconfig_connect_preferred "${iface}" && return 0 |
| 865 |
[[ ${associate_order} == "forcepreferred" \ |
| 866 |
|| ${associate_order} == "forceany" ]] \ |
| 867 |
&& iwconfig_force_preferred "${iface}" && return 0 |
| 868 |
[[ ${associate_order} == "any" || ${associate_order} == "forceany" ]] \ |
| 869 |
&& iwconfig_connect_not_preferred "${iface}" && return 0 |
| 870 |
fi |
| 871 |
|
| 872 |
e="associate with" |
| 873 |
[[ -z ${mac_APs} ]] && e="find" |
| 874 |
[[ ${preferred_only} == "force" || ${preferred_aps} == "forceonly" ]] \ |
| 875 |
&& e="force" |
| 876 |
e="Couldn't ${e} any access points on ${iface}" |
| 877 |
|
| 878 |
ESSID="adhoc_essid_${ifvar}" |
| 879 |
ESSID="${!ESSID}" |
| 880 |
if [[ -n ${ESSID} ]]; then |
| 881 |
ewarn "${e}" |
| 882 |
iwconfig_setup_specific "${iface}" ad-hoc |
| 883 |
return $? |
| 884 |
fi |
| 885 |
|
| 886 |
eerror "${e}" |
| 887 |
return 1 |
| 888 |
} |
| 889 |
|
| 890 |
# bool iwconfig_pre_start(char *iface) |
| 891 |
# |
| 892 |
# Start entry point |
| 893 |
# First we check if wireless extensions exist on the interface |
| 894 |
# If they are then we configue wireless |
| 895 |
iwconfig_pre_start() { |
| 896 |
local iface="$1" r=0 |
| 897 |
|
| 898 |
# We don't configure wireless if we're being called from |
| 899 |
# the background |
| 900 |
${IN_BACKGROUND} && return 0 |
| 901 |
|
| 902 |
save_options "ESSID" "" |
| 903 |
interface_exists "${iface}" || return 0 |
| 904 |
|
| 905 |
# We need to bring the interface up, as some cards do not register |
| 906 |
# in /proc/wireless until they are brought up. |
| 907 |
interface_up "${iface}" |
| 908 |
|
| 909 |
if ! iwconfig_exists "${iface}" ; then |
| 910 |
veinfo "Wireless extensions not found for ${iface}" |
| 911 |
return 0 |
| 912 |
fi |
| 913 |
|
| 914 |
iwconfig_defaults "${iface}" |
| 915 |
iwconfig_user_config "${iface}" |
| 916 |
|
| 917 |
# Set the base metric to be 2000 |
| 918 |
metric=2000 |
| 919 |
|
| 920 |
# Check for rf_kill - only ipw supports this at present, but other |
| 921 |
# cards may in the future. |
| 922 |
if [[ -e "/sys/class/net/${iface}/device/rf_kill" ]]; then |
| 923 |
if [[ $( < "/sys/class/net/${iface}/device/rf_kill" ) != 0 ]]; then |
| 924 |
eerror "Wireless radio has been killed for interface ${iface}" |
| 925 |
return 1 |
| 926 |
fi |
| 927 |
fi |
| 928 |
|
| 929 |
einfo "Configuring wireless network for ${iface}" |
| 930 |
|
| 931 |
# Are we a proper IEEE device? |
| 932 |
# Most devices reutrn IEEE 802.11b/g - but intel cards return IEEE |
| 933 |
# in lower case and RA cards return RAPCI or similar |
| 934 |
# which really sucks :( |
| 935 |
# For the time being, we will test prism54 not loading firmware |
| 936 |
# which reports NOT READY! |
| 937 |
x=$(iwconfig_get_type "${iface}") |
| 938 |
if [[ ${x} == "NOT READY!" ]]; then |
| 939 |
eerror "Looks like there was a probem loading the firmware for ${iface}" |
| 940 |
return 1 |
| 941 |
fi |
| 942 |
|
| 943 |
# Setup IFS incase parent script has modified it |
| 944 |
local IFS=$' '$'\n'$'\t' |
| 945 |
|
| 946 |
if iwconfig_configure "${iface}" ; then |
| 947 |
save_options "ESSID" "${ESSID}" |
| 948 |
return 0 |
| 949 |
fi |
| 950 |
|
| 951 |
eerror "Failed to configure wireless for ${iface}" |
| 952 |
iwconfig_defaults "${iface}" |
| 953 |
iwconfig "${iface}" txpower off 2>/dev/null |
| 954 |
unset ESSID ESSIDVAR |
| 955 |
interface_down "${iface}" |
| 956 |
return 1 |
| 957 |
} |
| 958 |
|
| 959 |
iwconfig_post_stop() { |
| 960 |
${IN_BACKGROUND} && return 0 |
| 961 |
interface_exists "${iface}" || return 0 |
| 962 |
iwconfig_defaults "${iface}" |
| 963 |
iwconfig "${iface}" txpower off 2>/dev/null |
| 964 |
} |
| 965 |
|
| 966 |
# vim: set ts=4 : |