Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- # vim:sw=8:ts=8:ai:foldmethod=indent
- # Compliance Test scanner tabajara.
- # You should be using your country's channels only, but who is me to judge...
- VERSION="2014.12.26.01"
- # Tested and confirmed working on:
- # NANOBEAM M5 19db with FW version(s):
- # XW.v5.5.9
- # XW.v5.5.10
- # Ubiquiti AirOS NanoBeam/NanoStation/Rocket XW compliance test kludge script
- # Please report other successful deployments in forums and share your improvements!
- # If I can merge it back, please say so in your posts. Thanks ':)
- cat <<EOF >/dev/null
- ******************************** READ ME FIRST ********************************
- MODE OF OPERATION:
- - Can be run manually for one scan, with no bandwidth change.
- - Designed to be run from rc.poststart, with "auto" argument. Will background
- itself.
- - Refuses to run two or more instances (checks for a lock file)
- - Refuses to run in AP mode (only managed/"station")
- - Refuses to run if channel list is enabled (if you have a list, you already
- did the hard work yourself!)
- - Writes to the system logger and /tmp/scriptname.log (only to console when in
- manual mode) with all it is doing. Keep the system log enabled!
- - Bandwitdh hopping: Read below!
- THEORY OF OPERATION:
- - Because of the quantity of available channels on compliance test mode, the
- station will take an eternity plus a day to link to some channels, and
- sometimes will not detect the AP on the site survey.
- - If the radio is associated while the script is running, it just sleeps.
- - If not associated, the script will limit the quantity of channels to be
- scanned, and submit a survey, pausing a little, then checking if it is
- associated. Rinse and repeat until no more channels are to be tested.
- - If bandwidth hopping is disabled, it will just start from scratch trying all
- channels again. To enable hopping, see below.
- BANDWIDTH HOPPING BEHAVIOR:
- - After trying all channels on current bandwidth mode, if it STILL is not
- associated, it will:
- * Note original bandwidth and count of retries it can make
- * Change to another bandwidth, reboot, scan
- * When every bandwidth is tested, it adds to the counter of retries
- * When retries count is reached, reverts to original bandwidth and wait.
- * If the association is successful, reset counter and wait.
- - This is managed by the "startup date" option. If it is UNCHECKED, the script
- will NEVER try to change BW mode. If CHECKED, the numeric DAY of the startup
- date is the count of tries the script will use to try scanning all the
- bandwidths. If it is 1, the script will stop trying new bandwidths after one
- try on all the ones. I would recommend setting it to 2 or 3 at most -- if it
- cannot do it in three times, the AP is dead.
- - Yeah, you only have 31 tries at most, but it is better than rebooting ad
- infinitum if the AP is down. You can always ask someone to unplug/plug the
- power and it will start over again from where it stopped.
- - We save every change. If you reboot the radio while it is not associated yet,
- it will continue scanning where it left off. Mind this!
- PARAMETERS:
- Set "bw_all" to the ordered list of your most used bandwidths.
- Experiment with "try_count" and "try_sleep" variables, on a radio you can
- locally SSH into and kill the script. In my experience too much "try_count" and
- too little "try_sleep" IS BAD.
- EOF
- # CHANGELOG:
- # - 2014.12.26.01
- # + Fixes:
- # Script name was hardcoded on install() - using basename $0 now.
- # - 2014.11.15.03
- # + Fixes:
- # Randomization of undetected channels being re-sorted before use
- # Wait in auto mode until system is up, so can write logs
- # + Cosmetic:
- # Split logged/printed channel list to at most 15 channels/line
- # Print board name and firmware version at startup
- # Print running parameters when unassociated
- # + Improvements:
- # Parameters f_log, f_config, max_log_lines added
- # Truncate f_log to $max_log_lines to save memory
- # Will read file $f_config for parameters on each loop - this means that
- # you can now modify the parameters at runtime!
- # Removing $f_lock file (rm /var/lock/CTscan.lock) makes the script exit.
- #
- # - 2014.11.03.32
- # + First internal release
- ### PARAMETERS ###
- # List of bandwidth ranges - change ranges in this order after trying the
- # current bandwidth and not associating.
- # Notice the trailing space for consistency. Keep it.
- # You could add 20MHz too but it is redundant as 20/40 does it.
- bw_all="20/40 30 10 5 25 "
- # Channel count to be locked on each try - will build a random list of N channels
- try_count=50
- # Wait time (seconds) for each channel list try.
- try_sleep=5
- # Wait time (seconds) on the main loop - the "are we associated yet?" scan
- loop_sleep=5
- # Max log lines to keep on $f_logfile
- max_log_lines=100
- ### END OF PARAMETERS ###
- # Files used (other than tmp ones)
- f_lock=/var/lock/$(basename $0).lock # refuse to run while this file is in place.
- f_persist=$0.persist # here we save our progress between reboots
- f_syscfg=/tmp/system.cfg # when changing bandwidth, will write this
- f_poststart=/etc/persistent/rc.poststart
- f_log=/tmp/$(basename $0).log
- f_config=$0.config
- # Bandwidth variables.
- bw_20_40="0 1 1 11naht40";
- bw_30="30 1 0 11naht20";
- bw_25="25 1 0 11naht20"
- bw_20="0 1 0 11naht20";
- bw_10="0 2 0 11naht20";
- bw_5="0 4 0 11naht20"
- getbw() { # get configured bandwidth in MHz, from the config file
- chanbw=$(sed -n 's/^radio\.1\.chanbw=//p' $f_syscfg)
- clksel=$(sed -n 's/^radio\.1\.clksel=//p' $f_syscfg)
- cwmmode=$(sed -n 's/^radio\.1\.cwm\.mode=//p' $f_syscfg)
- ieee_mode=$(sed -n 's/^radio\.1\.ieee_mode=//p' $f_syscfg)
- bw="$chanbw $clksel $cwmmode $ieee_mode"
- [ "$bw" = "$bw_20_40" ] && echo 20/40 && return 0
- [ "$bw" = "$bw_30" ] && echo 30 && return 0
- [ "$bw" = "$bw_25" ] && echo 25 && return 0
- [ "$bw" = "$bw_20" ] && echo 20 && return 0
- [ "$bw" = "$bw_10" ] && echo 10 && return 0
- [ "$bw" = "$bw_5" ] && echo 5 && return 0
- }
- setbw() { # set bandwith on config file
- if [ "$1" = "20/40" ]; then bw=$bw_20_40
- elif [ "$1" = "30" ]; then bw=$bw_30
- elif [ "$1" = "25" ]; then bw=$bw_25
- elif [ "$1" = "20" ]; then bw=$bw_20
- elif [ "$1" = "10" ]; then bw=$bw_10
- elif [ "$1" = "5" ]; then bw=$bw_5
- else return 1
- fi
- set - $bw
- sed -i "
- s/^\(radio\.1\.chanbw\)=.*$/\1=$1/
- s/^\(radio\.1\.clksel\)=.*$/\1=$2/
- s/^\(radio\.1\.cwm.mode\)=.*$/\1=$3/
- s/^\(radio\.1\.ieee_mode\)=.*$/\1=$4/
- " $f_syscfg
- }
- # Lines which the script will add/remove from poststart
- enableCTkey="### CTSCAN-enable"
- enableCTstr="echo '<option value=\"511\">Compliance Test</option>' >/etc/ccodes.inc $enableCTkey"
- enableSCkey="### CTSCAN-start"
- enableSCstr="/bin/sh /etc/persistent/$(basename $0) auto $enableSCkey"
- poststartCreate() { # creates poststart if not found
- if ! [ -f "$f_poststart" ]; then
- echo '#!/bin/sh' > $f_poststart
- chmod +x $f_poststart
- fi
- }
- install() { # add autostart
- poststartCreate
- sed -i "/$enableSCkey/d; $ a\
- $enableSCstr" $f_poststart
- echo "CTscan added to autostart, save and reboot to apply."
- }
- uninstall() { # remove autostart
- sed -i "/$enableSCkey/d" $f_poststart
- echo "CTscan removed from autostart, save and reboot to apply."
- }
- enableCT() { # enable compliance test.
- poststartCreate
- sed -i '/^radio\.\(1\.\)\?countrycode/s/=.*/=511/' $f_syscfg
- sed -i "/$enableCTkey/d; $ a\
- $enableCTstr" $f_poststart
- echo "Compliance test enabled, save and reboot to apply."
- }
- disableCT() { # disable compliance test.
- sed -i '/^radio\.\(1\.\)\?countrycode/s/=.*/=840/' $f_syscfg
- sed -i "/$enableCTkey/d" $f_poststart
- echo "Compliance test disabled, save and reboot to apply."
- echo "NOTE: You will then be required to set your country on the web interface!"
- }
- getstartupday() { # get date enabled, and if so, try count
- if fgrep -q 'system.date.status=enabled' $f_syscfg; then
- day=$(sed -n 's/^system\.date\.timestamp=..\([0-9]\{2\}\).*$/\1/p' $f_syscfg)
- echo $((day)) # remove leading zero if exists
- return 0
- else
- echo 0
- return 1
- fi
- }
- checkassoc() {
- # returns true if associated (mind the starting !)
- ! iwconfig ath0 | grep -q 'Access Point: Not-Associated'
- return $?
- }
- grepchan() {
- # Parses "iwlist scanning" command and returns only the channels found,
- # sorted, unique; removes channels already tried (kept in $f_fail temp file)
- sed -n "
- # Look for ESSID
- # XXX FIXME I hate putting variables inside a script... This is a point of
- # failure, if YOUR OWN SSID have some special character.
- /ESSID:$1/{
- # Join two lines down that
- N; N;
- # Catch only the frequency
- s/.*Frequency:\([0-9.]\+\) GHz.*/\1/;
- # Format it in MHz
- s/\.//; s/$/000/; s/^\([0-9]\{4\}\).*/\1/;
- # Print
- p;
- }" $f_scan | sort -n | uniq | grep -v -f $f_fail
- }
- scan() { # Main script loop. Will check, find, change BW
- if [ "$p" = "echolog" ]; then # Wait the system do fs check, mount
- while true; do
- sleep 2
- pgrep syscheck >&- || break
- done
- fi
- $p "CTscan version $VERSION: starting up."
- $p "Firmware version $(cat /etc/version) on a $(sed -n '/^board.name=/s/.*=//p' /etc/board.info)"
- bw_changes_stop=0 # when we already tried it all and gave up change bw, this will be 1
- bw_curr=$(getbw)
- while true; do
- # Reload config
- [ -f "$f_config" ] && source $f_config
- checkdisabled
- [ "$p" = "echolog" ] && sleep $loop_sleep # Early sleep is by design
- if ! checkassoc; then
- # Keeps the log file small
- cur_log_lines=$(wc -l <$f_log)
- [ "$cur_log_lines" -gt "$max_log_lines" ] && sed -i 1,$((cur_log_lines-max_log_lines))d $f_log
- # Find!
- $p 'Trying to find AP by locking onto some channels. Current parameters:'
- $p "bw_curr=$bw_curr bw_all='$bw_all' try_count=$try_count try_sleep=$try_sleep loop_sleep=$loop_sleep"
- if findchan; then
- # Success, reset/remove session and quiet down.
- bw_changes_stop=0
- [ -f "$f_persist" ] && rm $f_persist && savecfg
- [ "$p" = "echo" ] && return 0
- continue
- fi
- [ "$p" = "echo" ] && return 1 # Manual mode ends here
- if [ "$bw_changes_stop" = "1" ]; then
- # We have given up, keep in this bw until someone reboots
- continue
- fi
- bw_changes_allowed=$(getstartupday)
- if [ "$bw_changes_allowed" = "0" ]; then
- # bw change is disabled (startup date not enabled!), respect it and keep bw
- bw_changes_stop=1
- [ -f "$f_persist" ] && rm $f_persist && savecfg
- continue
- fi
- # bw change enabled, look for active session (or create one)
- getsession
- if [ "$bw_changes_stop" = "1" ]; then
- # We already tried looping ($bw_changes_allowed times) and failed in all.
- # The session file is here just to hint me to give up. So I will.
- # We should be on the last bandwidth set that worked, keep on it until reboot
- [ -f "$f_persist" ] && rm $f_persist && savecfg
- continue
- fi
- checkdisabled
- # DOWN HERE IS THE DESPAIR... REBOOTS
- if [ -n "$bw_new" ]; then
- # New bw waiting to try, do it
- sed -i "\,^bw_new=$bw_new$,d" $f_persist
- $p 'Rebooting on new bandwidth:' $bw_new 'MHz' # Shouldn't have time to read this, but...
- setbw $bw_new; savecfg; restart
- else
- # THE END OF THE INTERNET
- $p 'Raising retry counter'
- bw_try_count=$((bw_try_count+1))
- if [ "$bw_try_count" -lt "$bw_changes_allowed" ]; then
- # We can retry! Add bws again
- $p 'Resetting bandwidths to try again (try '$bw_try_count')'
- echobandwidths >> $f_persist
- sed -i "/^bw_try_count=/s/=.*/=$bw_try_count/" $f_persist
- else
- $p 'Retry count exceeded, will stay after reboot'
- echo "bw_changes_stop=1" > $f_persist
- fi
- fi
- # Revert to first bw and reboot
- $p 'Reverting to first bandwidth ('$bw_orig'MHz)'
- setbw $bw_orig; savecfg; restart
- # Now it is the end. Really. Remember me. Goodbye. Sniff.
- fi
- done
- }
- splitN() {
- qt_split=$1
- awk '
- {
- if( (NR%'$qt_split')==0 ) {
- printf("%s\n",$0)
- } else {
- printf("%s ",$0)
- }
- }
- END {
- if( (NR%'$qt_split')!=0 )print ""
- }'
- }
- findchan() {
- f_scan=$(mktemp -t) # temp file for iwconfig scanned list output
- f_fail=$(mktemp -t) # temp file for failed channels tried
- # grep -f pattern_file will barf if this file is empty
- echo ABCDEFGHIJKLMNOPQRSTUVWXYZ > $f_fail
- $p 'Enabling all channels'
- athchans -i ath0 all
- $p 'Available channels:'
- full_range=$(athchans -i ath0 -g | sed 's/ /\n/g')
- echo "$full_range" | splitN 15 | while read line; do $p $line; done
- $p 'Searching all channels range'
- iwlist ath0 scanning > $f_scan
- $p 'Active channels search complete'
- ssid=$(sed -n '/wireless\.[0-9]\.ssid=/{s/.*=//;p;q;}' $f_syscfg)
- $p 'SSID is set to: "'$ssid'"'
- checkdisabled
- # First test - try the channels that match the SSID, if any
- test_channels=$(grepchan '"'$ssid'"')
- failcode=1
- if [ -n "$test_channels" ]; then
- $p 'SSID found on full scan, channel(s): '$test_channels
- trychans && failcode=0
- echo "$test_channels" > $f_fail
- fi
- checkdisabled
- # Second test - try every other channel detected
- # Maybe hidden SSID and stuff.
- if [ "$failcode" = "1" ]; then
- test_channels=$(grepchan '')
- if [ -n "$test_channels" ]; then
- $p 'Trying all detected channels'
- trychans && failcode=0
- echo "$test_channels" >> $f_fail
- fi
- fi
- checkdisabled
- # Third -test - try everything else.
- if [ "$failcode" = "1" ]; then
- # Randomize full range list so each channel has a chance to be first
- full_range=$(echo "$full_range" | awk 'BEGIN{srand();}{print rand()"\t"$0}'|sort -n|cut -f2-)
- test_channels=$(echo "$full_range" | grep -v -f $f_fail)
- if [ -n "$test_channels" ]; then
- $p 'Trying the other undetected channels'
- trychans && failcode=0
- fi
- fi
- if [ "$failcode" = "1" ]; then
- $p 'Still unassociated!'
- else
- $p 'We are now officially associated! :)'
- $p $(iwlist ath0 channel|grep Current)
- fi
- rm $f_scan $f_fail
- return $failcode
- }
- trychans() {
- echo "$test_channels" | splitN $try_count | while read chan_list; do
- checkdisabled
- $p 'Trying at most '$try_count' channels in '$bw_curr'MHz bandwidth:'
- # Sort the channels printed on the screen, easy to read ;)
- echo "$chan_list" | sed 's/ /\n/g' | sort -n | splitN 15 |
- while read line; do $p $line; done
- # Now set the channels and
- athchans -i ath0 $chan_list
- #iwconfig ath0 commit # beams do not need this, but potato
- $p 'Surveying and waiting for '$try_sleep' seconds'
- # This somehow works faster than just waiting for a fix
- iwlist ath0 scanning >/dev/null
- # Wait...
- waitfor=$try_sleep
- while true; do
- checkassoc && break
- waitfor=$((waitfor-1))
- [ "$waitfor" = "0" ] && break
- sleep 1
- done
- # Check and get outta here
- checkassoc && break
- done
- # Return the results of the last check
- checkassoc
- return $?
- }
- getsession() {
- bw_new=""
- if [ ! -f "$f_persist" ]; then # no session file, create it
- $p 'Creating session file list of pending bandwidths to try'
- echo bw_orig=$bw_curr > $f_persist
- echo bw_changes_stop=0 >> $f_persist
- echo bw_try_count=0 >> $f_persist
- echobandwidths >> $f_persist
- fi
- source $f_persist
- }
- echobandwidths() {
- # reverse bandwidths to try, so the more preferred gets set after all others
- echo "$bw_all" | sed 's/ /\n/g' | sed '1!G;h;$!d' | while read bw; do
- [ "$bw" = "$bw_curr" ] && continue
- [ -z "$bw" ] && continue
- echo bw_new=$bw
- done
- }
- savecfg() {
- $p 'Saving'
- cfgmtd -w -p /etc/
- return 0
- }
- restart() {
- # I won't take chances with softrestart :)
- #/usr/etc/rc.d/rc.softrestart save
- rm $f_lock # just in case
- reboot
- exit 1 # just in case too
- }
- echolog() {
- logger $@
- echo $(date) $@ >> $f_log
- return 0
- }
- checkdisabled() {
- if [ ! -f "$f_lock" ]; then
- $p 'lock file removed, exiting at user request'
- exit 99
- fi
- }
- if [ "$1" = "enableCT" -o "$1" = "disableCT" -o "$1" = "install" -o "$1" = "uninstall" ]; then
- $1 # XXX this can be easily be overlooked - it calls the functions of same name ok?
- elif [ "$1" = "auto" -o "$1" = "manual" ]; then
- if ! grep -q 'countrycode=511' $f_syscfg; then
- echo 'Error: Compliance test mode is not enabled in config. Enable, save, reboot.'
- elif ! iwconfig ath0 | grep -q Mode:Managed; then
- echo 'Error: Only managed mode (station/client) supported!'
- elif ! grep -q 'wireless\.1\.scan_list\.status=disabled' $f_syscfg; then
- echo 'Error: Channel list has to be DISABLED!'
- elif [ -f $f_lock ]; then
- echo -e "Error: Refusing to run - file $f_lock already exists.\n\tKill existing script if any, remove it and try again."
- elif [ "$1" = "auto" ]; then
- p=echolog
- echo 'Backgrounding auto scan'
- scan &
- echo "$!" > $f_lock
- else
- p=echo
- scan
- fi
- return $?
- elif [ "$1" = "getbw" ]; then
- echo $(getbw)MHz
- elif [ "$1" = "setbw" -a -n "$2" ]; then
- setbw $2
- echo $(getbw)MHz
- else
- echo 'Invalid usage. Arguments available:'
- echo $0 '[ install | uninstall | enableCT | disableCT ]'
- echo $0 '[ auto | manual | getbw | setbw ]'
- echo
- echo 'install | uninstall'
- echo ' Add/remove call to this script to rc.poststart.'
- echo 'enableCT | disableCT'
- echo ' Adds/removes compliance test (only) to web interface and enables it in the'
- echo ' config file. Reboot to apply.'
- echo 'auto'
- echo ' Runs continually in the background trying to associate on all available channels'
- echo 'manual'
- echo ' One-time scan/association try, only on current bandwidth.'
- echo 'getbw/setbw'
- echo ' Shortcut to get/set current bandwidth. Valid values for setting: 20/40 30 25 20 10 5'
- echo ' Do not forget to save/reboot after setting bandwidth.'
- exit 1
- fi
- exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement