/bin/wifi: wifi scan for Quantenna.

Change-Id: I0fc143f31db387983face655c0212183c8142c87
diff --git a/wifi/quantenna.py b/wifi/quantenna.py
index e0f5a28..6c68029 100755
--- a/wifi/quantenna.py
+++ b/wifi/quantenna.py
@@ -31,7 +31,7 @@
 
 
 def _qcsapi(*args):
-  return subprocess.check_output(['qcsapi'] + list(args)).strip()
+  return subprocess.check_output(['qcsapi'] + [str(x) for x in args]).strip()
 
 
 def _brctl(*args):
@@ -78,15 +78,21 @@
   if not interface:
     return False
 
-  _qcsapi('rfenable', '0')
+  if mode == 'scan':
+    mode = 'sta'
+    scan = True
+  else:
+    scan = False
+
+  _qcsapi('rfenable', 0)
   _qcsapi('restore_default_config', 'noreboot')
 
   config = {
       'bw': opt.width,
-      'channel': '149' if opt.channel == 'auto' else opt.channel,
+      'channel': 149 if opt.channel == 'auto' else opt.channel,
       'mode': mode,
-      'pmf': '0',
-      'scs': '0',
+      'pmf': 0,
+      'scs': 0,
   }
   for param, value in config.iteritems():
     _qcsapi('update_config_param', 'wifi0', param, value)
@@ -107,14 +113,13 @@
   if mode == 'ap':
     _set_interface_in_bridge(opt.bridge, interface, True)
     _qcsapi('set_ssid', 'wifi0', opt.ssid)
-    _qcsapi('set_passphrase', 'wifi0', '0', os.environ['WIFI_PSK'])
-    _qcsapi('set_option', 'wifi0', 'ssid_broadcast',
-            '0' if opt.hidden_mode else '1')
-    _qcsapi('rfenable', '1')
-  elif mode == 'sta':
+    _qcsapi('set_passphrase', 'wifi0', 0, os.environ['WIFI_PSK'])
+    _qcsapi('set_option', 'wifi0', 'ssid_broadcast', int(not opt.hidden_mode))
+    _qcsapi('rfenable', 1)
+  elif mode == 'sta' and not scan:
     _set_interface_in_bridge(opt.bridge, interface, False)
     _qcsapi('create_ssid', 'wifi0', opt.ssid)
-    _qcsapi('ssid_set_passphrase', 'wifi0', opt.ssid, '0',
+    _qcsapi('ssid_set_passphrase', 'wifi0', opt.ssid, 0,
             os.environ['WIFI_CLIENT_PSK'])
     # In STA mode, 'rfenable 1' is already done by 'startprod'/'reload_in_mode'.
     # 'apply_security_config' must be called instead.
@@ -136,6 +141,29 @@
   return True
 
 
+def _parse_scan_result(line):
+  # Scan result format:
+  #
+  # "Quantenna1" 00:26:86:00:11:5f 60 56 1 2 1 2 0 15 80
+  # |            |                 |  |  | | | | | |  |
+  # |            |                 |  |  | | | | | |  Maximum bandwidth
+  # |            |                 |  |  | | | | | WPS flags
+  # |            |                 |  |  | | | | Qhop flags
+  # |            |                 |  |  | | | Encryption modes
+  # |            |                 |  |  | | Authentication modes
+  # |            |                 |  |  | Security protocols
+  # |            |                 |  |  Security enabled
+  # |            |                 |  RSSI
+  # |            |                 Channel
+  # |            MAC
+  # SSID
+  #
+  # The SSID may contain quotes and spaces. Split on whitespace from the right,
+  # making at most 10 splits, to preserve spaces in the SSID.
+  sp = line.strip().rsplit(None, 10)
+  return sp[0][1:-1], sp[1], int(sp[2]), float(sp[3]), int(sp[4]), int(sp[5])
+
+
 def set_wifi(opt):
   return _set('ap', opt)
 
@@ -150,7 +178,7 @@
     return False
 
   if _qcsapi('get_mode', 'wifi0') == 'Access point':
-    _qcsapi('rfenable', '0')
+    _qcsapi('rfenable', 0)
 
   return True
 
@@ -161,6 +189,39 @@
     return False
 
   if _qcsapi('get_mode', 'wifi0') == 'Station':
-    _qcsapi('rfenable', '0')
+    _qcsapi('rfenable', 0)
+
+  return True
+
+
+def scan_wifi(opt):
+  """Scan for APs."""
+  interface = _get_interface()
+  if not interface:
+    return False
+
+  if _qcsapi('rfstatus') == 'Off':
+    _set('scan', opt)
+
+  _qcsapi('start_scan', 'wifi0')
+  for _ in xrange(30):
+    if not int(_qcsapi('get_scanstatus', 'wifi0')):
+      break
+    time.sleep(1)
+  else:
+    raise utils.BinWifiException('start_scan timed out')
+
+  for i in xrange(int(_qcsapi('get_results_ap_scan', 'wifi0'))):
+    ssid, mac, channel, rssi, flags, protocols = _parse_scan_result(
+        _qcsapi('get_properties_ap', 'wifi0', i))
+    print 'BSS %s(on %s)' % (mac, interface)
+    print '\tfreq: %d' % (5000 + 5 * channel)
+    print '\tsignal: %.2f' % -rssi
+    print '\tSSID: %s' % ssid
+    if flags & 0x1:
+      if protocols & 0x1:
+        print '\tWPA:'
+      if protocols & 0x2:
+        print '\tRSN:'
 
   return True
diff --git a/wifi/quantenna_test.py b/wifi/quantenna_test.py
index ad6db09..e19c76e 100755
--- a/wifi/quantenna_test.py
+++ b/wifi/quantenna_test.py
@@ -18,7 +18,7 @@
 
 
 def fake_qcsapi(*args):
-  calls.append(list(args))
+  calls.append([str(x) for x in args])
   if args[0] == 'is_startprod_done':
     return '1' if ['startprod', 'wifi0'] in calls else '0'
   if args[0] == 'get_bssid':
@@ -233,5 +233,13 @@
   finally:
     shutil.rmtree(quantenna.WIFIINFO_PATH)
 
+
+@wvtest.wvtest
+def parse_scan_result_test():
+  result = '  " ssid with "quotes" " 00:11:22:33:44:55 40 25 0 0 0 0 0 1 40  '
+  wvtest.WVPASSEQ(quantenna._parse_scan_result(result),
+                  (' ssid with "quotes" ', '00:11:22:33:44:55', 40, 25, 0, 0))
+
+
 if __name__ == '__main__':
   wvtest.wvtest_main()
diff --git a/wifi/wifi.py b/wifi/wifi.py
index 01bba84..5531eee 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -532,6 +532,10 @@
     BinWifiException: If an expected interface is not found.
   """
   band = opt.band.split()[0]
+
+  if band == '5' and quantenna.scan_wifi(opt):
+    return True
+
   interface = iw.find_interface_from_band(
       band, iw.INTERFACE_TYPE.ap, opt.interface_suffix)
   if interface is None: