Home | History | Annotate | Download | only in network_WiFiTxRx
      1 #!/bin/bash
      2 
      3 # This script stops shill, associates with each test AP in turn,
      4 # and harvests signal strength and quality numbers for us, then restarts
      5 # shill so the old network can be reacquired and our test can complete
      6 
      7 set +o posix;
      8 shopt -s extglob;
      9 
     10 oldstderr=;
     11 stderrlog=;
     12 
     13 output_to_vtx () {
     14   # copy stderr to the next free vt so the user can see progress
     15   # on the DUT, otherwise they're just sitting there with no feedback
     16   # (if we can, that is - if openvt isn't there, just get on with it)
     17   if which openvt;
     18   then
     19     stderrlog=/tmp/$RANDOM.vtx.log;
     20     exec {oldstderr}>&2;
     21     exec 2>$stderrlog;
     22     tail --pid $$ -f $stderrlog >&$oldstderr &
     23     openvt -s -w -- tail --pid $$ -f $stderrlog &
     24   fi
     25 }
     26 
     27 close_vtx () {
     28   if [[ -f "$stderrlog" ]]; then
     29     rm "$stderrlog";
     30   fi;
     31 }
     32 
     33 progress () { echo "$@" 1>&2; }
     34 
     35 contains_modulations () {
     36   # check that at least one modulation in `wanted' is present in `supported'
     37   supported=$1;
     38   wanted=$2;
     39 
     40   case $supported in
     41     *[$wanted]*)
     42       return 0;
     43       ;;
     44   esac
     45 
     46   return 1;
     47 }
     48 
     49 # pick a WiFi interface to test
     50 find_wifi_if () {
     51   iface="$1";
     52 
     53   if [[ -z "$iface" ]]; then
     54     while read _iface _ignore && test -z "$iface"; do
     55       iface=$_iface;
     56     done < <(iwconfig 2>/dev/null | grep '^[a-z]');
     57   fi;
     58 
     59   test -n "$iface";
     60 }
     61 
     62 wifi_status () {
     63   # harvest the state of the target interface: modulation, essid and so forth:
     64   find_wifi_if "$1";
     65 
     66   if_80211=;
     67   if_essid=;
     68   if_mode=;
     69   if_ap=;
     70   if_rate=;
     71   if_txp=;
     72   if_quality=;
     73   if_signal=;
     74   if_freq=;
     75 
     76   # iwconfig's output is a pain to parse, but is stable.
     77   # the newer tools are much easier to parse, but they are
     78   # considered unstable by the authors, who specifically forbid
     79   # scraping their output until the specification stabilises.
     80   while read data; do
     81     case "$data" in
     82       $iface*)
     83         if_essid=${data##*ESSID:*(\")};
     84         if_essid=${if_essid%\"*};
     85         if_80211=${data%%+( )ESSID:*};
     86         if_80211=${if_80211#*802.11};
     87         ;;
     88       Mode:*)
     89         if_mode=${data#Mode:}
     90         if_mode=${if_mode%% *};
     91         if_ap=${data##*Access Point: };
     92         if_ap=${if_ap%% *};
     93         if_freq=${data##*Frequency:};
     94         if_freq=${if_freq%%+( )Access Point:*};
     95         if [[ "$if_ap" = "Not-Associated" ]]; then
     96           if_txp=${data##*Tx-Power=};
     97           fi
     98           ;;
     99       Bit\ Rate*)
    100         if_rate=${data%%+( )Tx-*};
    101         if_rate=${if_rate#Bit Rate=};
    102         if [[ -z $"if_txp" ]]; then
    103           if_txp=${data##*Tx-Power=};
    104           fi;
    105           ;;
    106       Link*)
    107         if_quality=${data%%+( )Signal*};
    108         if_quality=${if_quality#Link Quality=};
    109         if_signal=${data##*Signal level=};
    110         ;;
    111     esac;
    112   done < <(iwconfig $iface)
    113 }
    114 
    115 wifi_scan () {
    116   iface=$1;
    117 
    118   # Trigger a wifi scan. The DUT doesn't necessarily scan all frequencies
    119   # or remember APs on frequencies it isn't currently on, so we need to do
    120   # this at times to make sure we can interact with the test AP:
    121   progress Bringing up $iface;
    122   ifconfig $iface up 1>&2;
    123   progress Scanning for CrOS test ESSIDs;
    124 
    125   lofreq_aps="";
    126   hifreq_aps="";
    127 
    128   cell_freq=;
    129   cell_essid=;
    130 
    131   while read scan; do
    132     if [[ -z "$cell_freq" || -z "$cell_essid" ]]; then
    133       case "$scan" in
    134         Frequency:*)
    135           cell_freq=${scan##*Frequency:}
    136           cell_freq=${cell_freq%% *};
    137           cell_freq=${cell_freq:-0};
    138           ;;
    139         ESSID:*)
    140           cell_essid=${scan#*ESSID:\"};
    141           cell_essid=${cell_essid%\"*};
    142       esac;
    143     else
    144       if [[ "${cell_essid#CrOS-test-}" != "$cell_essid" ]]; then
    145         progress "Found test ESSID $cell_essid (Frequency: $cell_freq)";
    146         case "$cell_freq" in
    147           2*)
    148             lofreq_aps=${lofreq_aps}${lofreq_aps:+ }${cell_essid};
    149             ;;
    150           [45]*)
    151             hifreq_aps=${hifreq_aps}${hifreq_aps:+ }${cell_essid};
    152             ;;
    153         esac;
    154       else
    155         progress "Ignoring ESSID $cell_essid (Frequency: $cell_freq)";
    156       fi;
    157       cell_essid="";
    158       cell_freq="";
    159     fi;
    160   done < <(iwlist $iface scan);
    161 }
    162 
    163 wifi_find_essid () {
    164   iface=$1;
    165   target=$2;
    166 
    167   progress Bringing up $iface;
    168   ifconfig $iface up 1>&2;
    169   progress Scanning for ESSID $target;
    170   iwlist $iface scan | grep -q "ESSID:\"$target\"";
    171 }
    172 
    173 wifi_strength () {
    174   iface=$1;
    175   result=;
    176   macaddr=$(cat /sys/class/net/$iface/address)
    177   gateway=$(ip route show dev $iface to match 0/0|\
    178             if read x x g x; then echo $g; fi);
    179 
    180   progress Allowing link $gateway strength/quality readings to stabilise;
    181   ping -n -w 5 -c 5 $gateway 1>&2;
    182 
    183   progress Contacting AP at "/dev/tcp/$gateway/80" to collect TX strength;
    184   if exec {http}<>/dev/tcp/$gateway/80; then
    185     echo -e "GET /cgi-bin/txinfo HTTP/1.0\r\n\r" >&$http;
    186 
    187     while read mac strength other;
    188     do
    189       if [[ x${mac,,*} = x${macaddr,,*} ]]; then result=$strength; fi;
    190     done <&$http;
    191   fi;
    192 
    193   tx_db=${result:--100}" dBm";
    194 }
    195 
    196 wifi_associate () {
    197   wifi_status $iface;
    198 
    199   essid=${2:-"NO-ESSID-SUPPLIED"};
    200 
    201   if wifi_find_essid $iface $essid; then
    202     SECONDS=0;
    203     iwconfig $iface essid "$essid" 1>&2;
    204 
    205     until [[ x$if_essid = x$essid && x$if_ap != x'Not-Associated' ]]; do
    206       wifi_status $iface;
    207       progress "$SECONDS: $if_essid/$if_ap (want $essid)";
    208       sleep 2;
    209       if [[ $SECONDS -ge 30 ]]; then if_ap=failed; fi;
    210     done;
    211   else
    212     if_ap="Not-Found";
    213   fi
    214 
    215   test "$if_essid" = "$essid";
    216 }
    217 
    218 wifi_dhcp () {
    219   iface=$1;
    220   dhclient $iface \
    221     -sf /usr/local/sbin/dhclient-script \
    222     -lf /tmp/dhclient.leases 1>&2;
    223 }
    224 
    225 emit_result () {
    226   test=$2;
    227 
    228   if [[ "$1" = success ]]; then
    229 
    230     cat - <<EOF;
    231 802.11$test freq $if_freq quality $if_quality rx $if_signal tx $tx_db
    232 EOF
    233 
    234   else
    235 
    236     cat - <<EOF;
    237 802.11$test freq 0 quality 0/70 rx -100 dBm tx -100 dBm
    238 EOF
    239 
    240   fi;
    241 }
    242 
    243 test_association () {
    244   wlan_if=$1;
    245   ap_ssid=$2;
    246   mods=$3;
    247 
    248   if wifi_associate $wlan_if $ap_ssid; then
    249     wifi_dhcp     $wlan_if;
    250     wifi_strength $wlan_if;
    251     emit_result success $mods;
    252   else
    253     progress "WiFi Association failed for $wlan_if [$ap_ssid vs $if_ap]";
    254     emit_result failure $mods;
    255   fi;
    256 }
    257 
    258 output_to_vtx;
    259 
    260 wifi_status $1; # this will figure out all our initial if_ values
    261 modulations=$if_80211;
    262 
    263 progress "Start: $iface ($if_mode/$if_80211) ap $if_ap essid '$if_essid'";
    264 progress "Shutting down shill";
    265 stop shill 1>&2
    266 
    267 progress "Looking for test APs";
    268 wifi_scan $iface;
    269 
    270 progress "2.x GHz APs: $lofreq_aps";
    271 progress "4+  GHz APs: $hifreq_aps";
    272 
    273 if contains_modulations $modulations bg; then
    274   for ap in $lofreq_aps; do test_association $iface $ap bg; done;
    275 fi
    276 
    277 if contains_modulations $modulations an; then
    278   for ap in $hifreq_aps; do test_association $iface $ap an; done;
    279 fi
    280 
    281 start shill 1>&2;
    282 
    283 close_vtx;
    284