Merge "/bin/wifi:  Quantenna interface in bridge iff AP mode."
diff --git a/conman/connection_manager.py b/conman/connection_manager.py
index abfcb36..7379d88 100755
--- a/conman/connection_manager.py
+++ b/conman/connection_manager.py
@@ -85,6 +85,10 @@
     if self.ssid is None:
       raise ValueError('Command file does not specify SSID')
 
+    if self.wifi.initial_ssid == self.ssid:
+      logging.debug('Connected to WLAN at startup')
+      self.client_up = True
+
   def start_access_point(self):
     """Start an access point."""
 
@@ -147,7 +151,7 @@
 
     try:
       subprocess.check_output(self.WIFI_STOPCLIENT + ['-b', self.band],
-                            stderr=subprocess.STDOUT)
+                              stderr=subprocess.STDOUT)
       self.client_up = False
       logging.debug('Stopped wifi client on %s GHz', self.band)
     except subprocess.CalledProcessError as e:
@@ -237,11 +241,21 @@
 
     # If the ethernet file doesn't exist for any reason when conman starts,
     # check explicitly and run ifplugd.action to create the file.
-    if not os.path.exists(os.path.join(self._interface_status_dir,
-                                       self.ETHERNET_STATUS_FILE)):
-      ethernet_up = self.is_ethernet_up()
-      self.bridge.ethernet = ethernet_up
+    if not os.path.exists(os.path.join(self._interface_status_dir, 'eth0')):
+      ethernet_up = self.is_interface_up('eth0')
       self.ifplugd_action('eth0', ethernet_up)
+      self.bridge.ethernet = ethernet_up
+
+    # Do the same for wifi interfaces , but rather than explicitly setting that
+    # the wpa_supplicant link is up, attempt to attach to the wpa_supplicant
+    # control interface.
+    for wifi in self.wifi:
+      if not os.path.exists(
+          os.path.join(self._interface_status_dir, wifi.name)):
+        wifi_up = self.is_interface_up(wifi.name)
+        self.ifplugd_action(wifi.name, wifi_up)
+        if wifi_up:
+          wifi.attach_wpa_control(self._wpa_control_interface)
 
     for path, prefix in ((self._status_dir, self.GATEWAY_FILE_PREFIX),
                          (self._interface_status_dir, ''),
@@ -259,13 +273,16 @@
     self._interface_update_counter = 0
     self._try_wlan_after = {'5': 0, '2.4': 0}
 
-  def is_ethernet_up(self):
-    """Explicitly check whether ethernet is up.
+  def is_interface_up(self, interface_name):
+    """Explicitly check whether an interface is up.
 
     Only used on startup, and only if ifplugd file is missing.
 
+    Args:
+      interface_name:  The name of the interface to check.
+
     Returns:
-      Whether the ethernet link is up.
+      Whether the interface is up.
     """
     try:
       lines = subprocess.check_output(self.IP_LINK).splitlines()
@@ -273,7 +290,7 @@
       raise EnvironmentError('Failed to call "ip link": %r', e.message)
 
     for line in lines:
-      if 'eth0' in line and 'LOWER_UP' in line:
+      if interface_name in line and 'LOWER_UP' in line:
         return True
 
     return False
@@ -483,15 +500,16 @@
         match = re.match(self.COMMAND_FILE_REGEXP, filename)
         if match:
           band = match.group('band')
-          wifi = next(w for w in self.wifi if band in w.bands)
-          self._update_wlan_configuration(
-              self.WLANConfiguration(band, wifi, contents))
+          wifi = self.wifi_for_band(band)
+          if wifi:
+            self._update_wlan_configuration(
+                self.WLANConfiguration(band, wifi, contents))
       elif filename.startswith(self.ACCESS_POINT_FILE_PREFIX):
         match = re.match(self.ACCESS_POINT_FILE_REGEXP, filename)
         if match:
           band = match.group('band')
-          wifi = next(w for w in self.wifi if band in w.bands)
-          if band in self._wlan_configuration:
+          wifi = self.wifi_for_band(band)
+          if wifi and band in self._wlan_configuration:
             self._wlan_configuration[band].access_point = True
           logging.debug('AP enabled for %s GHz', band)
 
@@ -527,6 +545,15 @@
       if ifc.name == interface_name:
         return ifc
 
+  def wifi_for_band(self, band):
+    for wifi in self.wifi:
+      if band in wifi.bands:
+        return wifi
+
+    logging.error('No wifi interface for %s GHz.  wlan interfaces:\n%s',
+                  band, '\n'.join('%s: %r' %
+                                  (w.name, w.bands) for w in self.wifi))
+
   def ifplugd_action(self, interface_name, up):
     subprocess.call(self.IFPLUGD_ACTION + [interface_name,
                                            'up' if up else 'down'])
diff --git a/conman/connection_manager_test.py b/conman/connection_manager_test.py
index 19264f7..c22fbeb 100755
--- a/conman/connection_manager_test.py
+++ b/conman/connection_manager_test.py
@@ -76,6 +76,21 @@
 Client BSSID: f4:f5:e8:81:1b:a1
 """
 
+# See b/27328894.
+WIFI_SHOW_OUTPUT_ONE_RADIO_NO_5GHZ = """Band: 2.4
+RegDomain: 00
+Interface: wlan0  # 2.4 GHz ap
+BSSID: 00:50:43:02:fe:01
+AutoChannel: False
+Station List for band: 2.4
+
+Client Interface: wcli0  # 2.4 GHz client
+Client BSSID: 00:50:43:02:fe:02
+
+Band: 5
+RegDomain: 00
+"""
+
 IW_SCAN_OUTPUT = """BSS 00:11:22:33:44:55(on wcli0)
   SSID: s1
   Vendor specific: OUI f4:f5:e8, data: 01
@@ -178,13 +193,39 @@
   WIFI_SETCLIENT = ['echo', 'setclient']
   IFUP = ['echo', 'ifup']
   IFPLUGD_ACTION = ['echo', 'ifplugd.action']
-  # This simulates the output of 'ip link' when eth0 is up.
-  IP_LINK = ['echo', 'eth0 LOWER_UP']
 
   def __init__(self, *args, **kwargs):
+    self.interfaces_already_up = kwargs.pop('__test_interfaces_already_up',
+                                            ['eth0'])
+
+    wifi_interfaces_already_up = [ifc for ifc in self.interfaces_already_up
+                                  if ifc.startswith('wcli')]
+    for wifi in wifi_interfaces_already_up:
+      # wcli1 is always 5 GHz.  wcli0 always *includes* 2.4.
+      band = '5' if wifi == 'wcli1' else '2.4'
+      # This will happen in the super function, but in order for
+      # write_wlan_config to work we have to do it now.  This has to happen
+      # before the super function so that the files exist before the inotify
+      # registration.
+      self._config_dir = kwargs['config_dir']
+      self.write_wlan_config(band, 'my ssid', 'passphrase')
+
+      # Also create the wpa_supplicant socket to which to attach.
+      open(os.path.join(kwargs['wpa_control_interface'], wifi), 'w')
+
     super(ConnectionManager, self).__init__(*args, **kwargs)
+
+    for wifi in wifi_interfaces_already_up:
+      # pylint: disable=protected-access
+      self.interface_by_name(wifi)._initially_connected = True
+
     self.scan_has_results = False
 
+  @property
+  def IP_LINK(self):
+    return ['echo'] + ['%s LOWER_UP' % ifc
+                       for ifc in self.interfaces_already_up]
+
   def _update_access_point(self, wlan_configuration):
     client_was_up = wlan_configuration.client_up
     super(ConnectionManager, self)._update_access_point(wlan_configuration)
@@ -265,11 +306,6 @@
 
   # Non-overrides
 
-  def wifi_for_band(self, band):
-    for wifi in self.wifi:
-      if band in wifi.bands:
-        return wifi
-
   def access_point_up(self, band):
     if band not in self._wlan_configuration:
       return False
@@ -346,7 +382,7 @@
       self.run_once()
 
 
-def connection_manager_test(radio_config):
+def connection_manager_test(radio_config, **cm_kwargs):
   """Returns a decorator that does ConnectionManager test boilerplate."""
   def inner(f):
     """The actual decorator."""
@@ -378,7 +414,8 @@
                               wpa_control_interface=wpa_control_interface,
                               run_duration_s=run_duration_s,
                               interface_update_period=interface_update_period,
-                              wifi_scan_period_s=wifi_scan_period_s)
+                              wifi_scan_period_s=wifi_scan_period_s,
+                              **cm_kwargs)
 
         c.test_interface_update_period = interface_update_period
         c.test_wifi_scan_period = wifi_scan_period
@@ -710,5 +747,56 @@
   wvtest.WVPASS(c.wifi_for_band('5').current_route())
 
 
+
+@wvtest.wvtest
+@connection_manager_test(WIFI_SHOW_OUTPUT_ONE_RADIO_NO_5GHZ)
+def connection_manager_test_one_radio_no_5ghz(c):
+  """Test ConnectionManager for the case documented in b/27328894.
+
+  conman should be able to handle the lack of 5 GHz without actually
+  crashing.  Wired connections should not be affected.
+
+  Args:
+    c:  The ConnectionManager set up by @connection_manager_test.
+  """
+  # Make sure we've correctly set up the test; that there is no 5 GHz wifi
+  # interface.
+  wvtest.WVPASSEQ(c.wifi_for_band('5'), None)
+
+  c.set_ethernet(True)
+  wvtest.WVPASS(c.acs())
+  wvtest.WVPASS(c.internet())
+
+  # Make sure this doesn't crash.
+  c.write_wlan_config('5', 'my ssid', 'my psk')
+  c.run_once()
+  c.enable_access_point('5')
+  c.run_once()
+  c.disable_access_point('5')
+  c.run_once()
+  c.delete_wlan_config('5')
+  c.run_once()
+
+  # Make sure 2.4 still works.
+  c.write_wlan_config('2.4', 'my ssid', 'my psk')
+  c.run_once()
+  wvtest.WVPASS(c.wifi_for_band('2.4').acs())
+  wvtest.WVPASS(c.wifi_for_band('2.4').internet())
+  wvtest.WVPASS(c.wifi_for_band('2.4').current_route())
+
+
+@wvtest.wvtest
+@connection_manager_test(WIFI_SHOW_OUTPUT_ONE_RADIO,
+                         __test_interfaces_already_up=['eth0', 'wcli0'])
+def connection_manager_test_wifi_already_up(c):
+  """Test ConnectionManager when wifi is already up.
+
+  Args:
+    c:  The ConnectionManager set up by @connection_manager_test.
+  """
+  wvtest.WVPASS(c._connected_to_wlan(c.wifi_for_band('2.4')))
+  wvtest.WVPASS(c.wifi_for_band('2.4').current_route)
+
+
 if __name__ == '__main__':
   wvtest.wvtest_main()
diff --git a/conman/interface.py b/conman/interface.py
index 0a26959..9b9c653 100755
--- a/conman/interface.py
+++ b/conman/interface.py
@@ -306,6 +306,7 @@
     self.bands = kwargs.pop('bands', [])
     super(Wifi, self).__init__(*args, **kwargs)
     self._wpa_control = None
+    self.initial_ssid = None
 
   @property
   def wpa_supplicant(self):
@@ -331,8 +332,14 @@
         logging.error('Error attaching to wpa_supplicant: %s', e)
         return
 
-      self.wpa_supplicant = ('wpa_state=COMPLETED' in
-                             self._wpa_control.request('STATUS'))
+      for line in self._wpa_control.request('STATUS').splitlines():
+        if '=' not in line:
+          continue
+        key, value = line.split('=', 1)
+        if key == 'wpa_state':
+          self.wpa_supplicant = value == 'COMPLETED'
+        elif key == 'ssid' and not self._initialized:
+          self.initial_ssid = value
 
   def get_wpa_control(self, socket):
     return wpactrl.WPACtrl(socket)
@@ -367,3 +374,10 @@
             break
 
         self.update_routes()
+
+  def initialize(self):
+    """Unset self.initial_ssid, which is only relevant during initialization."""
+
+    self.initial_ssid = None
+    super(Wifi, self).initialize()
+
diff --git a/conman/interface_test.py b/conman/interface_test.py
index 6368a83..1e86125 100755
--- a/conman/interface_test.py
+++ b/conman/interface_test.py
@@ -89,7 +89,8 @@
 
   def request(self, request_type):
     if request_type == 'STATUS':
-      return 'foo\nwpa_state=COMPLETED\nbar' if self.connected else 'foo'
+      return ('foo\nwpa_state=COMPLETED\nssid=my ssid\nbar' if self.connected
+              else 'foo')
     else:
       raise ValueError('Invalid request_type %s' % request_type)
 
@@ -219,11 +220,15 @@
     w.detach_wpa_control()
     # pylint: disable=protected-access
     w._initially_connected = True
+    w._initialized = False
     w.attach_wpa_control(wpa_path)
     wpa_control = w._wpa_control
 
     # wpa_supplicant was already connected when we attached.
     wvtest.WVPASS(w.wpa_supplicant)
+    wvtest.WVPASSEQ(w.initial_ssid, 'my ssid')
+    w.initialize()
+    wvtest.WVPASSEQ(w.initial_ssid, None)
 
     # The wpa_supplicant process disconnects and terminates.
     wpa_control.add_event(Wifi.DISCONNECTED_EVENT)
diff --git a/ginstall/ginstall.py b/ginstall/ginstall.py
index c53f1af..1d233c6 100755
--- a/ginstall/ginstall.py
+++ b/ginstall/ginstall.py
@@ -72,6 +72,7 @@
     'SYSBLOCK': '/sys/block',
     'MMCBLK0BOOT0': '/dev/mmcblk0boot0',
     'MMCBLK0BOOT1': '/dev/mmcblk0boot1',
+    'MEMINFO': '/proc/meminfo',
 }
 
 MMC_RO_LOCK = {
@@ -132,6 +133,16 @@
   return open(F['ETCVERSION']).read().strip()
 
 
+def GetMemTotal():
+  total = open(F['MEMINFO']).readline()
+  total = total.split(' ')
+  total = filter(None, total)
+  if len(total) != 3:
+    print 'Error parsing /proc/meminfo'
+    return 0
+  return 1024 * int(total[1])
+
+
 def GetInternalHarddisk():
   for blkdev in sorted(glob.glob(F['SYSBLOCK'] + '/sd?')):
     dev_path = os.path.realpath(blkdev + '/device')
@@ -760,6 +771,9 @@
   Raises:
     Fatal: if install fails
   """
+  if GetPlatform() == 'GFHD254' and GetMemTotal() < 4*1e9:
+    print 'Skipping bootloader on 2GB lockdown.'
+    return
 
   loader_start = loader.filelike.tell()
   installed = False
diff --git a/ginstall/ginstall_test.py b/ginstall/ginstall_test.py
index 928cf58..8deac64 100755
--- a/ginstall/ginstall_test.py
+++ b/ginstall/ginstall_test.py
@@ -357,5 +357,14 @@
 
     return uloader, uloader_data
 
+  def testGetMemTotal(self):
+    ginstall.F['MEMINFO'] = 'testdata/proc/meminfo1'
+    total = ginstall.GetMemTotal()
+    self.assertTrue(total > 4*1e9)
+    ginstall.F['MEMINFO'] = 'testdata/proc/meminfo2'
+    total = ginstall.GetMemTotal()
+    self.assertTrue(total < 4*1e9)
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/ginstall/testdata/proc/meminfo1 b/ginstall/testdata/proc/meminfo1
new file mode 100644
index 0000000..0a6b71a
--- /dev/null
+++ b/ginstall/testdata/proc/meminfo1
@@ -0,0 +1,40 @@
+MemTotal:        4144364 kB
+MemFree:         2207124 kB
+MemAvailable:    2654112 kB
+Buffers:          146000 kB
+Cached:           354176 kB
+SwapCached:            0 kB
+Active:           317572 kB
+Inactive:         438000 kB
+Active(anon):     255532 kB
+Inactive(anon):    35648 kB
+Active(file):      62040 kB
+Inactive(file):   402352 kB
+Unevictable:           0 kB
+Mlocked:               0 kB
+HighTotal:       3932160 kB
+HighFree:        2175912 kB
+LowTotal:         212204 kB
+LowFree:           31212 kB
+SwapTotal:             0 kB
+SwapFree:              0 kB
+Dirty:                 0 kB
+Writeback:             0 kB
+AnonPages:        255416 kB
+Mapped:            81892 kB
+Shmem:             35788 kB
+Slab:              20328 kB
+SReclaimable:      10616 kB
+SUnreclaim:         9712 kB
+KernelStack:        2792 kB
+PageTables:         7436 kB
+NFS_Unstable:          0 kB
+Bounce:                0 kB
+WritebackTmp:          0 kB
+CommitLimit:     2072180 kB
+Committed_AS:     891408 kB
+VmallocTotal:     761856 kB
+VmallocUsed:       41868 kB
+VmallocChunk:     703484 kB
+CmaTotal:        2965504 kB
+CmaFree:         1427640 kB
diff --git a/ginstall/testdata/proc/meminfo2 b/ginstall/testdata/proc/meminfo2
new file mode 100644
index 0000000..cc3fab8
--- /dev/null
+++ b/ginstall/testdata/proc/meminfo2
@@ -0,0 +1,40 @@
+MemTotal:        2144364 kB
+MemFree:         2207200 kB
+MemAvailable:    2654188 kB
+Buffers:          146000 kB
+Cached:           354176 kB
+SwapCached:            0 kB
+Active:           317580 kB
+Inactive:         438000 kB
+Active(anon):     255540 kB
+Inactive(anon):    35648 kB
+Active(file):      62040 kB
+Inactive(file):   402352 kB
+Unevictable:           0 kB
+Mlocked:               0 kB
+HighTotal:       3932160 kB
+HighFree:        2175912 kB
+LowTotal:         212204 kB
+LowFree:           31288 kB
+SwapTotal:             0 kB
+SwapFree:              0 kB
+Dirty:                 0 kB
+Writeback:             0 kB
+AnonPages:        255420 kB
+Mapped:            81892 kB
+Shmem:             35788 kB
+Slab:              20316 kB
+SReclaimable:      10616 kB
+SUnreclaim:         9700 kB
+KernelStack:        2792 kB
+PageTables:         7432 kB
+NFS_Unstable:          0 kB
+Bounce:                0 kB
+WritebackTmp:          0 kB
+CommitLimit:     2072180 kB
+Committed_AS:     891408 kB
+VmallocTotal:     761856 kB
+VmallocUsed:       41868 kB
+VmallocChunk:     703484 kB
+CmaTotal:        2965504 kB
+CmaFree:         1427540 kB
diff --git a/logupload/client/prefix-logs.test b/logupload/client/prefix-logs.test
index 983edc8..3e5ca5e 100755
--- a/logupload/client/prefix-logs.test
+++ b/logupload/client/prefix-logs.test
@@ -17,9 +17,11 @@
 Sep 30 19:42:10 blob102 apenwarr: hello world
 " |
 ./prefix-logs | {
+  export IFS='[] '
+
   # prefix-logs always prepends an initial T: line as well as printing
   # additional ones on a schedule. Test the initial one.
-  read ts fac version timeval date time ntp junk
+  read level ts fac version timeval date time ntp junk
   WVPASSEQ "$fac" "T:"
   WVFAIL contains "$version" ' '
   WVPASS [ "$timeval" -gt 0 ]
@@ -27,15 +29,15 @@
   WVPASSEQ "$junk" ""
 
   # our actual log messages from above.
-  read ts fac msg
+  read level ts fac msg
   WVPASSEQ "$fac" "foo:"
   WVPASSEQ "$msg" "blue message ☺"
 
-  read ts fac msg
+  read level ts fac msg
   WVPASSEQ "$fac" "CRON:"
   WVPASSEQ "$msg" "pam_unix(cron:session): session closed for user root"
 
-  read ts fac msg
+  read level ts fac msg
   WVPASSEQ "$fac" "apenwarr:"
   WVPASSEQ "$msg" "hello world"
 }
diff --git a/sysmgr/peripheral/fancontrol.cc b/sysmgr/peripheral/fancontrol.cc
index 3bf2d64..a19afa9 100644
--- a/sysmgr/peripheral/fancontrol.cc
+++ b/sysmgr/peripheral/fancontrol.cc
@@ -119,6 +119,22 @@
                         };
 
 /*
+ * On Optimus Prime, AUX1 refers to the temperature sensor in the Quantenna SoC
+ * which controls the 11ac wifi interface. The granularity of the temperature
+ * readings are very coarse: increments of 5C.
+ */
+const FanControlParams FanControl::kGFRG250FanCtrlAux1Defaults = {
+                          temp_setpt    : 90,
+                          temp_max      : 109, /* fan speed is set to max when
+                                                  temperatures reaches 110C */
+                          temp_step     : 9,
+                          duty_cycle_min: 30,
+                          duty_cycle_max: 100,
+                          pwm_step      : 2,
+                          temp_overheat : 120,
+                        };
+
+/*
  * Defaults of Fan control parameters for GFSC100 (Spacecast).
  * There is no direct SOC temp input, so we use the remote sensor.
  * Mapping between external temp sensor and actual cpu temp was determined
@@ -185,6 +201,21 @@
                           temp_overheat : 120,
                         };
 
+/*
+ * AUX1 refers to the temperature sensor in the Quantenna SoC
+ * which controls the 11ac wifi interface. The granularity of the temperature
+ * readings are very coarse: increments of 5C.
+ */
+const FanControlParams FanControl::kGFHD254FanCtrlAux1Defaults = {
+                          temp_setpt    : 94,
+                          temp_max      : 110,
+                          temp_step     : 3,
+                          duty_cycle_min: 25,
+                          duty_cycle_max: 100,
+                          pwm_step      : 2,
+                          temp_overheat : 120,
+                        };
+
 const FanControlParams FanControl::kGFLT110FanCtrlSocDefaults = {
                           temp_setpt    : 0,  /* No fan */
                           temp_max      : 0,
@@ -202,7 +233,7 @@
 bool FanControl::Init(bool *gpio_mailbox_ready) {
 
   /* Check if the platform instance has been initialized
-   * 1) If run sysmgr,  the platformInstance_ would be initalized in
+   * 1) If run sysmgr,  the platform_ would be initalized in
    *    platformperipheral module.
    * 2) If run test_fan test util, the platformperipheral module won't be used.
    */
@@ -237,95 +268,116 @@
 }
 
 void FanControl::InitParams() {
-  pfan_ctrl_params_ = new FanControlParams[BRUNO_PARAMS_TYPES];
+  pfan_ctrl_params_ = new FanControlParams[BRUNO_PARAMS_TYPES_MAX];
 
-  uint8_t max;
-  switch (platform_ = platformInstance_->PlatformType()) {
+  switch (platform_->PlatformType()) {
     case BRUNO_GFMS100:
       /* Set thermal fan policy parameters of GFMS100 */
       pfan_ctrl_params_[BRUNO_SOC] = kGFMS100FanCtrlSocDefaults;
       pfan_ctrl_params_[BRUNO_IS_HDD] = kGFMS100FanCtrlHddDefaults;
-      max = BRUNO_IS_HDD;
       break;
     case BRUNO_GFHD100:
       /* Set thermal fan policy parameters of GFHD100 */
       pfan_ctrl_params_[BRUNO_SOC] = kGFHD100FanCtrlSocDefaults;
-      max = BRUNO_SOC;
       break;
     case BRUNO_GFHD200:
       pfan_ctrl_params_[BRUNO_SOC] = kGFHD200FanCtrlSocDefaults;
-      max = BRUNO_SOC;
       break;
     case BRUNO_GFHD254:
       pfan_ctrl_params_[BRUNO_SOC] = kGFHD254FanCtrlSocDefaults;
-      max = BRUNO_SOC;
+      pfan_ctrl_params_[BRUNO_AUX1] = kGFHD254FanCtrlAux1Defaults;
       break;
     case BRUNO_GFRG200:
       /* Set thermal fan policy parameters of GFRG200 */
       pfan_ctrl_params_[BRUNO_SOC] = kGFRG200FanCtrlSocDefaults;
-      max = BRUNO_SOC;
       break;
     case BRUNO_GFRG210:
       /* Set thermal fan policy parameters of GFRG210 */
       pfan_ctrl_params_[BRUNO_SOC] = kGFRG210FanCtrlSocDefaults;
       pfan_ctrl_params_[BRUNO_IS_HDD] = kGFRG210FanCtrlHddDefaults;
-      max = BRUNO_IS_HDD;
       break;
     case BRUNO_GFRG250:
       /* Set thermal fan policy parameters of GFRG250 */
       pfan_ctrl_params_[BRUNO_SOC] = kGFRG250FanCtrlSocDefaults;
       pfan_ctrl_params_[BRUNO_IS_HDD] = kGFRG250FanCtrlHddDefaults;
-      max = BRUNO_IS_HDD;
+      pfan_ctrl_params_[BRUNO_AUX1] = kGFRG250FanCtrlAux1Defaults;
       break;
     case BRUNO_GFSC100:
       /* Set thermal fan policy parameters of GFSC100 */
       pfan_ctrl_params_[BRUNO_SOC] = kGFSC100FanCtrlSocDefaults;
       pfan_ctrl_params_[BRUNO_IS_HDD] = kGFSC100FanCtrlHddDefaults;
-      max = BRUNO_IS_HDD;
       break;
     case BRUNO_GFLT110:
       pfan_ctrl_params_[BRUNO_SOC] = kGFLT110FanCtrlSocDefaults;
-      max = BRUNO_SOC;
       break;
     case BRUNO_UNKNOWN:
       LOG(LS_ERROR) << "Invalid platform type, ignore ... " << platform_;
-      max = BRUNO_SOC;
       break;
   }
 
   /* Check if an external fan control parameter table existing */
   dbgUpdateFanControlParams();
 
-  FanControlParams *pfan_ctrl;
-  uint8_t idx;
   /* Adjust the fan control parameters for calculation. */
-  for (idx = 0, pfan_ctrl = pfan_ctrl_params_; idx <= max; idx++, pfan_ctrl++) {
-    LOG(LS_INFO) << platformInstance_->PlatformName()
-                 << ((idx == BRUNO_SOC)? "_SOC" : "_HDD") << std::endl
-                 << " Tsetpt: "    << pfan_ctrl->temp_setpt << std::endl
-                 << " Tmax: "      << pfan_ctrl->temp_max << std::endl
-                 << " Tstep: "     << pfan_ctrl->temp_step << std::endl
-                 << " Dmin: "      << pfan_ctrl->duty_cycle_min << std::endl
-                 << " Dmax: "      << pfan_ctrl->duty_cycle_max << std::endl
-                 << " PWMstep: "   << pfan_ctrl->pwm_step << std::endl
-                 << " Toverheat: " << pfan_ctrl->temp_overheat << std::endl;
+  for (int i = 0; i < BRUNO_PARAMS_TYPES_MAX; i++) {
+    const char *suffix;
+    switch(i) {
+      case BRUNO_SOC:
+        suffix = "_SOC";
+        break;
+
+      case BRUNO_IS_HDD:
+        suffix = "_HDD";
+        if (!platform_->has_hdd()) {
+          LOG(LS_INFO) << "platform does not have hdd.";
+          continue;
+        }
+        break;
+
+      case BRUNO_AUX1:
+        suffix = "_AUX1";
+        if (!platform_->has_aux1()) {
+          LOG(LS_INFO) << "platform does not have aux1.";
+          continue;
+        }
+        break;
+
+      default:
+        suffix = "_UNKNOWN";
+        LOG(LS_ERROR) << "Unknown type in fan param array";
+        continue;
+    }
+
+    LOG(LS_INFO)
+        << platform_->PlatformName()
+        << suffix << std::endl
+        << " Tsetpt: "    << pfan_ctrl_params_[i].temp_setpt << std::endl
+        << " Tmax: "      << pfan_ctrl_params_[i].temp_max << std::endl
+        << " Tstep: "     << pfan_ctrl_params_[i].temp_step << std::endl
+        << " Dmin: "      << pfan_ctrl_params_[i].duty_cycle_min << std::endl
+        << " Dmax: "      << pfan_ctrl_params_[i].duty_cycle_max << std::endl
+        << " PWMstep: "   << pfan_ctrl_params_[i].pwm_step << std::endl
+        << " Toverheat: " << pfan_ctrl_params_[i].temp_overheat << std::endl;
   }
 }
 
 
 bool FanControl::AdjustSpeed(
-      uint16_t soc_temp, uint16_t hdd_temp, uint16_t fan_speed) {
+      uint16_t soc_temp, uint16_t hdd_temp, uint16_t aux1_temp,
+      uint16_t fan_speed) {
   bool ret = true;
   uint16_t new_duty_cycle_pwm;
 
   LOG(LS_VERBOSE) << __func__ << ": soc_temp=" << soc_temp
-                  << " hdd_temp=" << hdd_temp << " fan_speed=" << fan_speed;
+                  << " hdd_temp=" << hdd_temp << " aux1_temp=" << aux1_temp
+                  << " fan_speed=" << fan_speed;
 
   do {
     /* Get new SOC PWM per the current SOC and HDD temperatures */
 
     /* Get new duty cycle per SOC and HDD temperatures */
-    ComputeDutyCycle(soc_temp, hdd_temp, fan_speed, &new_duty_cycle_pwm);
+    ComputeDutyCycle(soc_temp, hdd_temp, aux1_temp, fan_speed,
+        &new_duty_cycle_pwm);
 
     LOG(LS_INFO) << __func__ << ": duty_cycle_pwm = " << new_duty_cycle_pwm;
     if (new_duty_cycle_pwm != duty_cycle_pwm_) {
@@ -370,7 +422,7 @@
   *phdd_temp = 0;
   uint16_t hdd_temp;
 
-  if (platformInstance_->PlatformHasHdd() == true) {
+  if (platform_->has_hdd() == true) {
     std::string buf = "hdd-temperature /dev/sda";
     /* Create vector to hold hdd temperature words */
     std::vector<std::string> tokens;
@@ -410,97 +462,86 @@
   return true;
 }
 
+uint16_t FanControl::__ComputeDutyCycle(
+  uint16_t temp,
+  uint16_t fan_speed,
+  const FanControlParams &params) {
+
+  uint16_t  compute_duty_cycle = duty_cycle_pwm_;
+  if (temp > params.temp_max) {
+    compute_duty_cycle = params.duty_cycle_max;
+  }
+  else if (temp > (params.temp_setpt + params.temp_step)) {
+    if (fan_speed == kFanSpeedNotSpinning) {
+      compute_duty_cycle = params.duty_cycle_min;
+    }
+    else if (duty_cycle_pwm_ < params.duty_cycle_max) {
+      /* 1. Possibly, the fan still stops due to duty_cycle_pwm_ is not large
+       *    enough. Continue increase the duty cycle.
+       * 2. Or the fan is running, but it's not fast enough to cool down
+       *    the unit.
+       */
+      compute_duty_cycle = duty_cycle_pwm_ + params.pwm_step;
+      if (compute_duty_cycle > params.duty_cycle_max)
+        compute_duty_cycle = params.duty_cycle_max;
+    }
+  }
+  else if (temp < (params.temp_setpt - params.temp_step)) {
+    if ((fan_speed == kFanSpeedNotSpinning) ||
+        (duty_cycle_pwm_ < params.pwm_step)) {
+      compute_duty_cycle = kPwmMinValue;
+    }
+    else {
+      /* Reduce fan pwm if temp is lower than
+       * the (temp_setpt - temp_step) and plus fan is still spinning
+       */
+      compute_duty_cycle = duty_cycle_pwm_ - params.pwm_step;
+    }
+  }
+  return compute_duty_cycle;
+}
 
 void FanControl::ComputeDutyCycle(
   uint16_t soc_temp,
   uint16_t hdd_temp,
+  uint16_t aux1_temp,
   uint16_t fan_speed,
   uint16_t *new_duty_cycle_pwm) {
 
   uint16_t  soc_compute_duty_cycle = 0;
   uint16_t  hdd_compute_duty_cycle = 0;
+  uint16_t  aux1_compute_duty_cycle = 0;
   FanControlParams  *psoc = &pfan_ctrl_params_[BRUNO_SOC];
   FanControlParams  *phdd = get_hdd_fan_ctrl_parms();
+  FanControlParams  *paux1 = get_aux1_fan_ctrl_parms();
 
   LOG(LS_VERBOSE) << __func__ << " - duty_cycle_pwm_ = " << duty_cycle_pwm_
                << " i/p soc_temp=" << soc_temp
                << " hdd_temp="     << hdd_temp
+               << " aux1_temp="    << aux1_temp
                << " fan_speed="    << fan_speed;
 
   /* check SOC temps */
   if (psoc) {
-    soc_compute_duty_cycle = duty_cycle_pwm_;
-    if (soc_temp > psoc->temp_max) {
-      soc_compute_duty_cycle = psoc->duty_cycle_max;
-    }
-    else if (soc_temp > (psoc->temp_setpt + psoc->temp_step)) {
-      if (fan_speed == kFanSpeedNotSpinning) {
-        soc_compute_duty_cycle = psoc->duty_cycle_min;
-      }
-      else if (duty_cycle_pwm_ < psoc->duty_cycle_max) {
-        /* 1. Possibly, the fan still stops due to duty_cycle_pwm_ is not large
-         *    enough. Continue increase the duty cycle.
-         * 2. Or the fan is running, but it's not fast enough to cool down
-         *    the unit.
-         */
-        soc_compute_duty_cycle = duty_cycle_pwm_ + psoc->pwm_step;
-        if (soc_compute_duty_cycle > psoc->duty_cycle_max)
-          soc_compute_duty_cycle = psoc->duty_cycle_max;
-      }
-    }
-    else if (soc_temp < (psoc->temp_setpt - psoc->temp_step)) {
-      if ((fan_speed == kFanSpeedNotSpinning) ||
-          (duty_cycle_pwm_ < psoc->pwm_step)) {
-        soc_compute_duty_cycle = kPwmMinValue;
-      }
-      else {
-        /* Reduce fan pwm if soc_temp is lower than
-         * the (temp_setpt - temp_step) and plus fan is still spinning
-         */
-        soc_compute_duty_cycle = duty_cycle_pwm_ - psoc->pwm_step;
-      }
-    }
+    soc_compute_duty_cycle = __ComputeDutyCycle(soc_temp, fan_speed, *psoc);
   }
 
   /* check HDD temps */
   if (phdd) {
-    hdd_compute_duty_cycle = duty_cycle_pwm_;
-    if (if_hdd_temp_over_temp_max(hdd_temp, phdd) == true) {
-      hdd_compute_duty_cycle = phdd->duty_cycle_max;
-    }
-    else if (if_hdd_temp_over_temp_setpt(hdd_temp, phdd) == true) {
-      if (fan_speed == kFanSpeedNotSpinning) {
-        hdd_compute_duty_cycle = phdd->duty_cycle_min;
-      }
-      else if (duty_cycle_pwm_ < phdd->duty_cycle_max) {
-        /* 1. Possibly, the fan still stops due to duty_cycle_pwm_ is not large
-         *    enough. Continue increase the duty cycle.
-         * 2. Or the fan is running, but it's not fast enough to cool down
-         *    the unit.
-         */
-        hdd_compute_duty_cycle = duty_cycle_pwm_ + phdd->pwm_step;
-        if (hdd_compute_duty_cycle > phdd->duty_cycle_max)
-          hdd_compute_duty_cycle = phdd->duty_cycle_max;
-      }
-    }
-    else if (if_hdd_temp_lower_than_temp_setpt(hdd_temp, phdd) == true) {
-      if ((fan_speed == kFanSpeedNotSpinning) ||
-          (duty_cycle_pwm_ < phdd->pwm_step)) {
-        hdd_compute_duty_cycle = kPwmMinValue;
-      }
-      else {
-        /* Reduce fan pwm if both soc_temp and hdd_temp are lower than
-         * their (temp_setpt - temp_step) and plus fan is still spinning
-         */
-        hdd_compute_duty_cycle = duty_cycle_pwm_ - phdd->pwm_step;
-      }
-    }
+    hdd_compute_duty_cycle = __ComputeDutyCycle(hdd_temp, fan_speed, *phdd);
+  }
+
+  /* check HDD temps */
+  if (paux1) {
+    aux1_compute_duty_cycle = __ComputeDutyCycle(aux1_temp, fan_speed, *paux1);
   }
 
   LOG(LS_INFO) << "soc_duty_cycle_pwm = " << soc_compute_duty_cycle << " "
-               << "hdd_duty_cycle_pwm = " << hdd_compute_duty_cycle;
+               << "hdd_duty_cycle_pwm = " << hdd_compute_duty_cycle << " "
+               << "aux1_duty_cycle_pwm = " << aux1_compute_duty_cycle;
 
   *new_duty_cycle_pwm = MAX(soc_compute_duty_cycle, hdd_compute_duty_cycle);
+  *new_duty_cycle_pwm = MAX(*new_duty_cycle_pwm, aux1_compute_duty_cycle);
 
   LOG(LS_INFO) << "new_duty_cycle_pwm = " << *new_duty_cycle_pwm;
 
@@ -541,43 +582,17 @@
 }
 
 FanControlParams *FanControl::get_hdd_fan_ctrl_parms() {
-  FanControlParams  *ptr = NULL;
-  if (platformInstance_->PlatformHasHdd() == true) {
-    ptr = &pfan_ctrl_params_[BRUNO_IS_HDD];
+  if (platform_->has_hdd() == true) {
+    return &pfan_ctrl_params_[BRUNO_IS_HDD];
   }
-  return ptr;
+  return NULL;
 }
 
-
-bool FanControl::if_hdd_temp_over_temp_max(const uint16_t hdd_temp, const FanControlParams *phdd) const {
-  bool  ret = false;  /* if no hdd params, default is false */
-  if ((phdd != NULL) && (hdd_temp > phdd->temp_max)) {
-    ret = true;
+FanControlParams *FanControl::get_aux1_fan_ctrl_parms() {
+  if (platform_->has_aux1() == true) {
+    return &pfan_ctrl_params_[BRUNO_AUX1];
   }
-  return ret;
-}
-
-
-bool FanControl::if_hdd_temp_over_temp_setpt(const uint16_t hdd_temp, const FanControlParams *phdd) const {
-  bool  ret = false;  /* if no hdd params, default is false */
-  if ((phdd != NULL) && (hdd_temp > (phdd->temp_setpt + phdd->temp_step))) {
-    ret = true;
-  }
-  return ret;
-}
-
-
-bool FanControl::if_hdd_temp_lower_than_temp_setpt(const uint16_t hdd_temp, const FanControlParams *phdd) const {
-  bool  ret = true;   /* if no hdd params, default is true */
-  if (phdd != NULL) {
-    if (hdd_temp < (phdd->temp_setpt - phdd->temp_step)) {
-      ret = true;
-    }
-    else {
-      ret = false;
-    }
-  }
-  return ret;
+  return NULL;
 }
 
 
@@ -587,7 +602,7 @@
   if (params_table_file.is_open()) {
     LOG(LS_INFO) << FAN_CONTROL_PARAMS_FILE << " existing...";
     dbgGetFanControlParamsFromParamsFile(BRUNO_SOC);
-    if (platformInstance_->PlatformHasHdd() == true) {
+    if (platform_->has_hdd() == true) {
       dbgGetFanControlParamsFromParamsFile(BRUNO_IS_HDD);
     }
   }
@@ -606,7 +621,7 @@
   /* Get the search platform keyword in the table file: GFMS100_SOC,
    * GFMS100_HDD...
    */
-  std::string buf = platformInstance_->PlatformName();
+  std::string buf = platform_->PlatformName();
   switch (fc_idx) {
     case BRUNO_SOC:
       buf += "_SOC";
@@ -614,6 +629,9 @@
     case BRUNO_IS_HDD:
       buf += "_HDD";
       break;
+    case BRUNO_AUX1:
+      buf += "_AUX1";
+      break;
     default:
       buf += "_UNKNOWN";
       LOG(LS_WARNING) << "Invalid fc_index: " << fc_idx << std::endl;
@@ -622,7 +640,7 @@
 
   LOG(LS_INFO) << buf << std::endl;
 
-  std::string result = platformInstance_->GetLine((char *)FAN_CONTROL_PARAMS_FILE, &buf);
+  std::string result = platform_->GetLine((char *)FAN_CONTROL_PARAMS_FILE, &buf);
   if (result.empty() == true)
     return false;
 
diff --git a/sysmgr/peripheral/fancontrol.h b/sysmgr/peripheral/fancontrol.h
index 95ff95a..2e552e3 100644
--- a/sysmgr/peripheral/fancontrol.h
+++ b/sysmgr/peripheral/fancontrol.h
@@ -50,7 +50,8 @@
   enum FanControlParamsTypes {
     BRUNO_SOC = 0,
     BRUNO_IS_HDD,
-    BRUNO_PARAMS_TYPES
+    BRUNO_AUX1,
+    BRUNO_PARAMS_TYPES_MAX
   };
 
   static const unsigned int kPwmDefaultStartup;
@@ -68,13 +69,16 @@
 
   static const FanControlParams kGFRG250FanCtrlSocDefaults;
   static const FanControlParams kGFRG250FanCtrlHddDefaults;
+  static const FanControlParams kGFRG250FanCtrlAux1Defaults;
 
   static const FanControlParams kGFSC100FanCtrlSocDefaults;
   static const FanControlParams kGFSC100FanCtrlHddDefaults;
 
   static const FanControlParams kGFHD100FanCtrlSocDefaults;
   static const FanControlParams kGFHD200FanCtrlSocDefaults;
+
   static const FanControlParams kGFHD254FanCtrlSocDefaults;
+  static const FanControlParams kGFHD254FanCtrlAux1Defaults;
 
   static const FanControlParams kGFLT110FanCtrlSocDefaults;
 
@@ -84,16 +88,16 @@
         duty_cycle_pwm_(kPwmMinValue),
         duty_cycle_startup_(kPwmDefaultStartup),
         period_(DUTY_CYCLE_PWM_MAX_VALUE-1),
-        platform_(BRUNO_GFHD100),
         pfan_ctrl_params_(NULL),
-        platformInstance_(platform) {}
+        platform_(platform) {}
 
   virtual ~FanControl();
 
   bool Init(bool *gpio_mailbox_ready);
   void Terminate(void);
   bool DrivePwm(uint16_t duty_cycle);
-  bool AdjustSpeed(uint16_t soc_temp, uint16_t hdd_temp, uint16_t fan_speed);
+  bool AdjustSpeed(uint16_t soc_temp, uint16_t hdd_temp, uint16_t aux1_temp,
+                   uint16_t fan_speed);
   void GetHddTemperature(uint16_t *phdd_temp);
   void GetOverheatTemperature(uint16_t *poverheat_temp);
 
@@ -101,7 +105,9 @@
 
   void InitParams(void);
   std::string ExecCmd(char* cmd, std::string *pattern);
-  void ComputeDutyCycle(uint16_t soc_temp, uint16_t hdd_temp,
+  uint16_t __ComputeDutyCycle(uint16_t temp, uint16_t fan_speed,
+                  const FanControlParams &params);
+  void ComputeDutyCycle(uint16_t soc_temp, uint16_t hdd_temp, uint16_t aux1_temp,
                         uint16_t fan_speed, uint16_t *new_duty_cycle_pwm);
 
   void dbgUpdateFanControlParams(void);
@@ -125,14 +131,11 @@
    * idx BRUNO_SOC: depending upon GFMS100 (Bruno-IS) or GFHD100 (Thin Bruno);
    * idx BRUNO_IS_HDD: use by HDD GFMS100
    * */
-  enum BrunoPlatformTypes platform_;
   FanControlParams *pfan_ctrl_params_;
-  Platform *platformInstance_;
+  Platform *platform_;
 
   FanControlParams *get_hdd_fan_ctrl_parms();
-  bool if_hdd_temp_over_temp_max(const uint16_t hdd_temp, const FanControlParams *phdd) const;
-  bool if_hdd_temp_over_temp_setpt(const uint16_t hdd_temp, const FanControlParams *phdd) const;
-  bool if_hdd_temp_lower_than_temp_setpt(const uint16_t hdd_temp, const FanControlParams *phdd) const;
+  FanControlParams *get_aux1_fan_ctrl_parms();
 
   DISALLOW_COPY_AND_ASSIGN(FanControl);
 };
diff --git a/sysmgr/peripheral/mailbox.cc b/sysmgr/peripheral/mailbox.cc
index 2af9e2e..d1050fd 100644
--- a/sysmgr/peripheral/mailbox.cc
+++ b/sysmgr/peripheral/mailbox.cc
@@ -10,6 +10,7 @@
 const std::string  Mailbox::kMailboxFanPercentFile = "/tmp/gpio/fanpercent";
 const std::string  Mailbox::kMailboxFanSpeedFile = "/tmp/gpio/fanspeed";
 const std::string  Mailbox::kMailboxCpuTemperatureFile = "/tmp/gpio/cpu_temperature";
+const std::string  Mailbox::kMailboxAux1TemperatureFile = "/tmp/gpio/aux1_temperature";
 const std::string  Mailbox::kMailboxCpuVoltageFile = "/tmp/gpio/cpu_voltage";
 const std::string  Mailbox::kMailboxReadyFile = "/tmp/gpio/ready";
 
@@ -50,6 +51,23 @@
 }
 
 
+/* Read AUX1 temperature
+ * rtn = true, aux1_temperature - current AUX1 temperature
+ *       false aux1_temperature - an invalid value
+ */
+bool Mailbox::ReadAux1Temperature(float *aux1_temperature) {
+  std::string value_str;
+  bool  rtn;
+
+  *aux1_temperature = 0.0;
+  rtn = ReadValueString(kMailboxAux1TemperatureFile, &value_str);
+  if (rtn == true) {
+    rtn = ConvertStringToFloat(value_str, aux1_temperature);
+  }
+  return rtn;
+}
+
+
 /* Read CPU voltage
  *
  * Return:
diff --git a/sysmgr/peripheral/mailbox.h b/sysmgr/peripheral/mailbox.h
index 5ea3a43..c680ecf 100644
--- a/sysmgr/peripheral/mailbox.h
+++ b/sysmgr/peripheral/mailbox.h
@@ -39,6 +39,7 @@
   static const std::string  kMailboxFanPercentFile;
   static const std::string  kMailboxFanSpeedFile;
   static const std::string  kMailboxCpuTemperatureFile;
+  static const std::string  kMailboxAux1TemperatureFile;
   static const std::string  kMailboxCpuVoltageFile;
   static const std::string  kMailboxReadyFile;
 
@@ -47,6 +48,7 @@
 
   bool ReadFanSpeed(uint16_t *fan_speed);
   bool ReadSocTemperature(float *soc_temperature);
+  bool ReadAux1Temperature(float *soc_temperature);
   bool ReadSocVoltage(std::string *soc_voltage);
   bool WriteFanDutyCycle(uint16_t duty_cycle);
   bool ReadFanDutyCycle(uint16_t *duty_cycle);
diff --git a/sysmgr/peripheral/peripheralmon.cc b/sysmgr/peripheral/peripheralmon.cc
index 5f520ac..fafb6e4 100644
--- a/sysmgr/peripheral/peripheralmon.cc
+++ b/sysmgr/peripheral/peripheralmon.cc
@@ -17,16 +17,21 @@
 void PeripheralMon::Probe(void) {
   bruno_base::TimeStamp now = bruno_base::Time();
   float soc_temperature;
+  float aux1_temperature = 0.0;
   uint16_t  fan_speed = 0;
   std::string soc_voltage;
 
-  if (platform_->PlatformHasHdd() &&
+  if (platform_->has_hdd() &&
       bruno_base::TimeIsLaterOrEqual(next_time_hdd_temp_check_, now)) {
     fan_control_->GetHddTemperature(&hdd_temp_);
     LOG(LS_INFO) << "hdd_temperature (new):" << hdd_temp_;
     next_time_hdd_temp_check_ = bruno_base::TimeAfter(hdd_temp_interval_);
   }
 
+  if (platform_->has_aux1()) {
+    ReadAux1Temperature(&aux1_temperature);
+  }
+
   if (gpio_mailbox_ready == false)
     gpio_mailbox_ready = CheckIfMailBoxIsReady();
 
@@ -34,25 +39,27 @@
     bool read_soc_temperature = ReadSocTemperature(&soc_temperature);
     ReadSocVoltage(&soc_voltage);
 
-    if (platform_->PlatformHasFan()) {
+    if (platform_->has_fan()) {
       ReadFanSpeed(&fan_speed);
     }
 
     LOG(LS_INFO) << "voltage:" << soc_voltage
                  << "  soc_temperature:" << soc_temperature
                  << "  hdd_temperature:" << hdd_temp_
+                 << "  aux1_temperature:" << aux1_temperature
                  << "  fanspeed:" << fan_speed;
 
     if (read_soc_temperature) {
       Overheating(soc_temperature);
     }
 
-    if (platform_->PlatformHasFan()) {
+    if (platform_->has_fan()) {
       /* If failed to read soc_temperature, don't change PWM */
       if (read_soc_temperature) {
         fan_control_->AdjustSpeed(
                       static_cast<uint16_t>(soc_temperature),
                       hdd_temp_,
+                      aux1_temperature,
                       fan_speed);
       } else {
         LOG(LS_INFO) << "Not change PWM due to fail to read soc_temperature";
@@ -95,8 +102,7 @@
   }
 }
 
-void PeripheralMon::Init(int interval, int hdd_temp_interval) {
-  interval_ = interval;
+void PeripheralMon::Init(int hdd_temp_interval) {
   hdd_temp_interval_ = hdd_temp_interval;
   next_time_hdd_temp_check_ = bruno_base::Time(); // = now
   overheating_ = 0;
diff --git a/sysmgr/peripheral/peripheralmon.h b/sysmgr/peripheral/peripheralmon.h
index 26bdcc1..b9a4855 100644
--- a/sysmgr/peripheral/peripheralmon.h
+++ b/sysmgr/peripheral/peripheralmon.h
@@ -19,24 +19,21 @@
 class GpIoFanSpeed;
 class PeripheralMon : public Mailbox {
  public:
-  PeripheralMon(Platform *plat, unsigned int interval = 5000,
-                unsigned int hdd_temp_interval = 300000)
-      : platform_(plat), fan_control_(new FanControl(plat)), interval_(interval),
-    hdd_temp_interval_(hdd_temp_interval), hdd_temp_(0),
+  PeripheralMon(Platform *plat)
+      : platform_(plat), fan_control_(new FanControl(plat)),
+        hdd_temp_interval_(300000), hdd_temp_(0),
     last_time_(0), next_time_hdd_temp_check_(0),
     gpio_mailbox_ready(false) {
   }
   virtual ~PeripheralMon();
   void Probe(void);
-
-  void Init(int interval, int hdd_temp_interval);
+  void Init(int hdd_temp_interval);
 
  private:
   void Overheating(float soc_temperature);
 
   Platform* platform_;
   bruno_base::scoped_ptr<FanControl> fan_control_;
-  int interval_;
   int hdd_temp_interval_;
   uint16_t hdd_temp_;
   unsigned int overheating_;
diff --git a/sysmgr/peripheral/platform.cc b/sysmgr/peripheral/platform.cc
index 0d206b6..23572a0 100644
--- a/sysmgr/peripheral/platform.cc
+++ b/sysmgr/peripheral/platform.cc
@@ -9,18 +9,18 @@
 
 /* Platform table */
 const Platform Platform::kPlatformTable[] = {
-         /* model     type           hdd    fan */
-  Platform("GFMS100", BRUNO_GFMS100, true,  true),
-  Platform("GFHD100", BRUNO_GFHD100, false, true),
-  Platform("GFHD200", BRUNO_GFHD200, false, false),
-  Platform("GFRG200", BRUNO_GFRG200, false, true),
-  Platform("GFRG210", BRUNO_GFRG210, true,  true),
-  Platform("GFRG250", BRUNO_GFRG250, true,  true),
-  Platform("GFSC100", BRUNO_GFSC100, true,  true),
-  Platform("GFLT110", BRUNO_GFLT110, false, false),
-  Platform("GFLT120", BRUNO_GFLT110, false, false),
-  Platform("GFHD254", BRUNO_GFHD254, false, true),
-  Platform("UNKNOWN PLATFORM", BRUNO_UNKNOWN, false, false),
+         /* model     type           hdd    aux1   fan */
+  Platform("GFMS100", BRUNO_GFMS100, true,  false, true),
+  Platform("GFHD100", BRUNO_GFHD100, false, false, true),
+  Platform("GFHD200", BRUNO_GFHD200, false, false, false),
+  Platform("GFRG200", BRUNO_GFRG200, false, false, true),
+  Platform("GFRG210", BRUNO_GFRG210, true,  false, true),
+  Platform("GFRG250", BRUNO_GFRG250, true,  true,  true),
+  Platform("GFSC100", BRUNO_GFSC100, true,  false, true),
+  Platform("GFLT110", BRUNO_GFLT110, false, false, false),
+  Platform("GFLT120", BRUNO_GFLT110, false, false, false),
+  Platform("GFHD254", BRUNO_GFHD254, false, true, true),
+  Platform("UNKNOWN PLATFORM", BRUNO_UNKNOWN, false, false,  false),
 };
 
 void Platform::Init(void) {
@@ -39,6 +39,7 @@
       name_ = kPlatformTable[i].name_;
       type_ = kPlatformTable[i].type_;
       has_hdd_ = kPlatformTable[i].has_hdd_;
+      has_aux1_ = kPlatformTable[i].has_aux1_;
       has_fan_ = kPlatformTable[i].has_fan_;
       break;
     }
diff --git a/sysmgr/peripheral/platform.h b/sysmgr/peripheral/platform.h
index 642a57a..80e0a74 100644
--- a/sysmgr/peripheral/platform.h
+++ b/sysmgr/peripheral/platform.h
@@ -33,11 +33,13 @@
 
  public:
   explicit Platform()
-      : name_("Unknown"), type_(BRUNO_UNKNOWN), has_hdd_(false), has_fan_(false) {}
+      : name_("Unknown"), type_(BRUNO_UNKNOWN), has_hdd_(false),
+        has_aux1_(false), has_fan_(false) {}
 
   Platform(const std::string& name, BrunoPlatformTypes type, bool has_hdd,
-           bool has_fan)
-      : name_(name), type_(type), has_hdd_(has_hdd), has_fan_(has_fan) {}
+           bool has_aux1, bool has_fan)
+      : name_(name), type_(type), has_hdd_(has_hdd), has_aux1_(has_aux1),
+        has_fan_(has_fan) {}
 
   virtual ~Platform() {}
 
@@ -46,14 +48,16 @@
   void Init(void);
   std::string PlatformName(void) const { return name_; }
   enum BrunoPlatformTypes PlatformType(void) const { return type_; }
-  bool PlatformHasHdd(void) const { return has_hdd_; }
-  bool PlatformHasFan(void) const { return has_fan_; }
+  bool has_hdd(void) const { return has_hdd_; }
+  bool has_fan(void) const { return has_fan_; }
+  bool has_aux1(void) const { return has_aux1_; }
   std::string GetLine(char *file, std::string *pattern);
 
  private:
   std::string name_;
   BrunoPlatformTypes type_;
   bool has_hdd_;
+  bool has_aux1_;
   bool has_fan_;
 
   void GetPlatformType(void);
diff --git a/sysmgr/sysmgr.cc b/sysmgr/sysmgr.cc
index 8b67912..fcdc1df 100644
--- a/sysmgr/sysmgr.cc
+++ b/sysmgr/sysmgr.cc
@@ -45,7 +45,7 @@
   Platform* platform = new Platform();
   platform->Init();
   PeripheralMon* pmon = new PeripheralMon(platform);
-  pmon->Init(FLAG_interval, FLAG_hdd_temp_interval);
+  pmon->Init(FLAG_hdd_temp_interval);
 
   for (;;) {
     pmon->Probe();
diff --git a/sysmgr/utest/test_fan.cc b/sysmgr/utest/test_fan.cc
index fe228d3..8907595 100644
--- a/sysmgr/utest/test_fan.cc
+++ b/sysmgr/utest/test_fan.cc
@@ -20,6 +20,8 @@
   DEFINE_int(soc_high, 10, "SOC High temperature");
   DEFINE_int(hdd_low, 1, "HDD Low temperature");
   DEFINE_int(hdd_high, 10, "HDD High temperature");
+  DEFINE_int(aux1_low, 1, "AUX1 Low temperature");
+  DEFINE_int(aux1_high, 10, "AUX1 High temperature");
   DEFINE_int(percent, 0, "Percentage of the maximum speed the fan starts at");
   DEFINE_int(count, 10, "Repeat times");
   DEFINE_int(interval, 1, "Interval");
@@ -45,7 +47,7 @@
   }
 
   bruno_platform_peripheral::Platform platform(
-      "Unknown", bruno_platform_peripheral::BRUNO_UNKNOWN, false, false);
+      "Unknown", bruno_platform_peripheral::BRUNO_UNKNOWN, false, false, false);
   platform.Init();
   bruno_platform_peripheral::FanControl fan_control(&platform);
 
@@ -56,38 +58,43 @@
   fan_control.DrivePwm(FLAG_percent);
   sleep(2);
 
-  int i, h;
+  int i, h, g;
 
   LOG(LS_VERBOSE) << "soc_low=" << FLAG_soc_low << " soc_high=" << FLAG_soc_high
-                  << " hdd_low=" << FLAG_hdd_low << " hdd_high=" << FLAG_hdd_high;
+                  << " hdd_low=" << FLAG_hdd_low << " hdd_high=" << FLAG_hdd_high
+                  << " aux1_low=" << FLAG_aux1_low << " aux1_high=" << FLAG_aux1_high;
 
-  for (i=FLAG_soc_low, h=FLAG_hdd_low;
-       ((i<FLAG_soc_high) || (h<FLAG_hdd_high)); i++, h++) {
+  for (i=FLAG_soc_low, h=FLAG_hdd_low, g=FLAG_aux1_low;
+       ((i<FLAG_soc_high) || (h<FLAG_hdd_high) || (g<FLAG_aux1_high));
+       i++, h++, g++) {
     for (int j=0; j<FLAG_count; ++j) {
       fan_control.ReadFanSpeed(&fan_speed);
       fan_control.AdjustSpeed(
-                  static_cast<uint16_t>(i), static_cast<uint16_t>(h), fan_speed);
+                  static_cast<uint16_t>(i), static_cast<uint16_t>(h), static_cast<uint16_t>(g), fan_speed);
       fan_control.ReadFanSpeed(&fan_speed);
       fan_control.ReadSocVoltage(&soc_voltage);
       LOG(LS_INFO) << "voltage:" << soc_voltage
                    << "  emu-soc_temperature:" << i
                    << "  emu-hdd_temperature:" << h
+                   << "  emu-aux1_temperature:" << g
                    << "  fanspeed:" << fan_speed;
       sleep(FLAG_interval);
     }
   }
   if (FLAG_dec_temp == true) {
-    for (i=FLAG_soc_high, h=FLAG_hdd_high;
-         ((i>FLAG_soc_low) || (h>FLAG_hdd_low)); i--, h--) {
+    for (i=FLAG_soc_high, h=FLAG_hdd_high, g=FLAG_aux1_high;
+         ((i>FLAG_soc_low) || (h>FLAG_hdd_low) || (g>FLAG_aux1_low));
+          i--, h--, g--) {
       for (int j=0; j<FLAG_count; ++j) {
         fan_control.ReadFanSpeed(&fan_speed);
         fan_control.AdjustSpeed(
-                    static_cast<uint16_t>(i), static_cast<uint16_t>(h), fan_speed);
+                    static_cast<uint16_t>(i), static_cast<uint16_t>(h), static_cast<uint16_t>(g), fan_speed);
         fan_control.ReadFanSpeed(&fan_speed);
         fan_control.ReadSocVoltage(&soc_voltage);
         LOG(LS_INFO) << "voltage:" << soc_voltage
                      << "  emu-soc_temperature:" << i
                      << "  emu-hdd_temperature:" << h
+                     << "  emu-aux1_temperature:" << g
                      << "  fanspeed:" << fan_speed;
         sleep(FLAG_interval);
       }
diff --git a/taxonomy/ethernet.py b/taxonomy/ethernet.py
index 11bbdb9..f8966f3 100644
--- a/taxonomy/ethernet.py
+++ b/taxonomy/ethernet.py
@@ -59,6 +59,7 @@
     '50:2e:5c': ['htc'],
     '64:a7:69': ['htc'],
     '7c:61:93': ['htc'],
+    '84:7a:88': ['htc'],
     '90:e7:c4': ['htc'],
     'b4:ce:f6': ['htc'],
     'd8:b3:77': ['htc'],
diff --git a/taxonomy/pcaptest.py b/taxonomy/pcaptest.py
index fda85b8..a44a7b6 100644
--- a/taxonomy/pcaptest.py
+++ b/taxonomy/pcaptest.py
@@ -11,7 +11,13 @@
   # devices for which we have a pcap but have decided not to add
   # to the database, generally because the device is not common
   # enough.
+  ('Unknown', './testdata/pcaps/Amazon Fire Phone 2.4GHz.pcap'),
+  ('Unknown', './testdata/pcaps/Amazon Fire Phone 5GHz Broadcast.pcap'),
+  ('Unknown', './testdata/pcaps/Amazon Fire Phone 5GHz Specific.pcap'),
+  ('Unknown', './testdata/pcaps/Amazon Fire Phone 5GHz.pcap'),
   ('Unknown', './testdata/pcaps/ASUS Transformer TF300 2.4GHz.pcap'),
+  ('Unknown', './testdata/pcaps/Blackberry Bold 9930 2.4GHz.pcap'),
+  ('Unknown', './testdata/pcaps/Blackberry Bold 9930 5GHz.pcap'),
   ('Unknown', './testdata/pcaps/iPhone 2 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/iPhone 3 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/iPhone 3GS 2.4GHz.pcap'),
@@ -29,6 +35,7 @@
   ('Unknown', './testdata/pcaps/MediaTek MT7610U 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/Motorola Droid 2 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/Motorola Droid 3 2.4GHz.pcap'),
+  ('Unknown', './testdata/pcaps/Motorola Droid Razr Maxx 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/Nexus One 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/Nokia Lumia 920 2.4GHz.pcap'),
   ('Unknown', './testdata/pcaps/Nokia Lumia 920 5GHz.pcap'),
diff --git a/taxonomy/testdata/dhcp.leases b/taxonomy/testdata/dhcp.leases
index c5565d4..4bbfb3d 100644
--- a/taxonomy/testdata/dhcp.leases
+++ b/taxonomy/testdata/dhcp.leases
@@ -42,5 +42,6 @@
 1432237016 d0:23:db:a2:e5:02 192.168.42.33 iPhoone-4s
 1432237016 00:26:4a:c2:89:58 192.168.42.33 iPhoone-3GS
 1432237016 74:c2:46:fc:bb:d6 192.168.42.34 AmazonDashButton
-1432237016 04:0c:ce:cf:40:2c 192.168.42.34 MacbookAir2010
-1432237016 8c:2d:aa:9c:ce:0f 192.168.42.34 iPood-5
+1432237016 04:0c:ce:cf:40:2c 192.168.42.35 MacbookAir2010
+1432237016 8c:2d:aa:9c:ce:0f 192.168.42.36 iPood-5
+1432237016 dc:86:d8:a0:c8:de 192.168.42.37 iPhoone-5c
diff --git a/taxonomy/testdata/dhcp.signatures b/taxonomy/testdata/dhcp.signatures
index b7e818a..5a1ef1d 100644
--- a/taxonomy/testdata/dhcp.signatures
+++ b/taxonomy/testdata/dhcp.signatures
@@ -36,3 +36,4 @@
 74:c2:46:fc:bb:d6 1,3,6
 04:0c:ce:cf:40:2c 1,3,6,15,119,95,252,44,46
 8c:2d:aa:9c:ce:0f 1,3,6,15,119,252
+dc:86:d8:a0:c8:de 1,3,6,15,119,252
diff --git a/taxonomy/testdata/pcaps/Amazon Fire Phone 2.4GHz.pcap b/taxonomy/testdata/pcaps/Amazon Fire Phone 2.4GHz.pcap
new file mode 100644
index 0000000..0ec6d0c
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Amazon Fire Phone 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz Broadcast.pcap b/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz Broadcast.pcap
new file mode 100644
index 0000000..41f5653
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz Broadcast.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz Specific.pcap b/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz Specific.pcap
new file mode 100644
index 0000000..0ef5716
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz Specific.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz.pcap b/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz.pcap
new file mode 100644
index 0000000..30713b3
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Amazon Fire Phone 5GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Blackberry Bold 9930 2.4GHz.pcap b/taxonomy/testdata/pcaps/Blackberry Bold 9930 2.4GHz.pcap
new file mode 100644
index 0000000..78fce83
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Blackberry Bold 9930 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Blackberry Bold 9930 5GHz.pcap b/taxonomy/testdata/pcaps/Blackberry Bold 9930 5GHz.pcap
new file mode 100644
index 0000000..8e86f86
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Blackberry Bold 9930 5GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/HTC One 2.4GHz.pcap b/taxonomy/testdata/pcaps/HTC One 2.4GHz.pcap
new file mode 100644
index 0000000..4c495c2
--- /dev/null
+++ b/taxonomy/testdata/pcaps/HTC One 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/HTC One 5GHz.pcap b/taxonomy/testdata/pcaps/HTC One 5GHz.pcap
new file mode 100644
index 0000000..08282a5
--- /dev/null
+++ b/taxonomy/testdata/pcaps/HTC One 5GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/LG G2 2.4GHz.pcap b/taxonomy/testdata/pcaps/LG G2 2.4GHz.pcap
new file mode 100644
index 0000000..3cbfbf2
--- /dev/null
+++ b/taxonomy/testdata/pcaps/LG G2 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/LG G2 5GHz.pcap b/taxonomy/testdata/pcaps/LG G2 5GHz.pcap
new file mode 100644
index 0000000..cf559e2
--- /dev/null
+++ b/taxonomy/testdata/pcaps/LG G2 5GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Motorola Droid Razr Maxx 2.4GHz.pcap b/taxonomy/testdata/pcaps/Motorola Droid Razr Maxx 2.4GHz.pcap
new file mode 100644
index 0000000..2779597
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Motorola Droid Razr Maxx 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Samsung Galaxy S2+ 2.4GHz.pcap b/taxonomy/testdata/pcaps/Samsung Galaxy S2+ 2.4GHz.pcap
new file mode 100644
index 0000000..32e0a3f
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Samsung Galaxy S2+ 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Samsung Galaxy S2+ 5GHz.pcap b/taxonomy/testdata/pcaps/Samsung Galaxy S2+ 5GHz.pcap
new file mode 100644
index 0000000..ccfd9cc
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Samsung Galaxy S2+ 5GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Samsung Galaxy S3 2.4GHz.pcap b/taxonomy/testdata/pcaps/Samsung Galaxy S3 2.4GHz.pcap
new file mode 100644
index 0000000..704479f
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Samsung Galaxy S3 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Samsung Galaxy S3 5GHz.pcap b/taxonomy/testdata/pcaps/Samsung Galaxy S3 5GHz.pcap
new file mode 100644
index 0000000..13e27b6
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Samsung Galaxy S3 5GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz Broadcast.pcap b/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz Broadcast.pcap
new file mode 100644
index 0000000..d16dd98
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz Broadcast.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz Specific.pcap b/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz Specific.pcap
new file mode 100644
index 0000000..14b6070
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz Specific.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz.pcap b/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz.pcap
new file mode 100644
index 0000000..6f687b9
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 5c 2.4GHz.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 5c 5GHz Broadcast.pcap b/taxonomy/testdata/pcaps/iPhone 5c 5GHz Broadcast.pcap
new file mode 100644
index 0000000..9d0d15b
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 5c 5GHz Broadcast.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 5c 5GHz Specific.pcap b/taxonomy/testdata/pcaps/iPhone 5c 5GHz Specific.pcap
new file mode 100644
index 0000000..d411276
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 5c 5GHz Specific.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 5c 5GHz.pcap b/taxonomy/testdata/pcaps/iPhone 5c 5GHz.pcap
new file mode 100644
index 0000000..936ea1f
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 5c 5GHz.pcap
Binary files differ
diff --git a/taxonomy/wifi.py b/taxonomy/wifi.py
index 7790bc9..b7cfaa6 100644
--- a/taxonomy/wifi.py
+++ b/taxonomy/wifi.py
@@ -130,9 +130,13 @@
     'wifi|probe:0,1,3,45,50,htcap:0060,htagg:03,htmcs:000000ff|assoc:0,1,48,50,127,221(0050f2,2),45,htcap:006c,htagg:03,htmcs:000000ff|os:hpprinter':
         ('', 'HP Printer', '2.4GHz'),
 
-    'wifi|probe:0,1,45,127,191,221(506f9a,16),221(001018,2),221(00904c,51),htcap:006f,vhtcap:03800032|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,vhtcap:03800032|oui:htc':
+    'wifi3|probe:0,1,45,127,191,221(001018,2),221(00904c,51),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:03800032,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),cap:0011,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:03800032,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e008,extcap:0000000000000040|oui:htc':
         ('BCM4335', 'HTC One', '5GHz'),
-    'wifi|probe:0,1,50,3,45,127,221(506f9a,16),221(001018,2),221(00904c,51),htcap:102d|assoc:0,1,33,36,48,50,45,221(001018,2),221(0050f2,2),htcap:102d|oui:htc':
+    'wifi3|probe:0,1,3,45,127,191,221(001018,2),221(00904c,51),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:03800032,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),cap:0011,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:03800032,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e008,extcap:0000000000000040|oui:htc':
+        ('BCM4335', 'HTC One', '5GHz'),
+    'wifi3|probe:0,1,50,45,127,221(001018,2),221(00904c,51),htcap:102d,htagg:17,htmcs:000000ff,extcap:0000000000000040|assoc:0,1,33,36,48,50,45,221(001018,2),221(0050f2,2),cap:0431,htcap:102d,htagg:17,htmcs:000000ff,txpow:1408|oui:htc':
+        ('BCM4335', 'HTC One', '2.4GHz'),
+    'wifi3|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),htcap:102d,htagg:17,htmcs:000000ff,extcap:0000000000000040|assoc:0,1,33,36,48,50,45,221(001018,2),221(0050f2,2),cap:0431,htcap:102d,htagg:17,htmcs:000000ff,txpow:1408|oui:htc':
         ('BCM4335', 'HTC One', '2.4GHz'),
 
     'wifi3|probe:0,1,45,221(0050f2,8),221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,wps:HTC_VLE_U|assoc:0,1,50,48,45,221(0050f2,2),cap:0431,htcap:012c,htagg:03,htmcs:000000ff':
@@ -266,6 +270,13 @@
     'wifi3|probe:0,1,50,3,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0020,htagg:1a,htmcs:000000ff,intwrk:ff,extcap:00000004|assoc:0,1,33,36,48,50,45,70,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:0020,htagg:1a,htmcs:000000ff,txpow:1403|os:ios':
         ('BCM4334', 'iPhone 5', '2.4GHz'),
 
+    'wifi3|probe:0,1,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0062,htagg:1a,htmcs:000000ff,intwrk:02,extcap:00000004|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1805|os:ios':
+        ('BCM4334', 'iPhone 5c', '5GHz'),
+    'wifi3|probe:0,1,50,3,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0020,htagg:1a,htmcs:000000ff,intwrk:02,extcap:00000004|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:0020,htagg:1a,htmcs:000000ff,txpow:1704|os:ios':
+        ('BCM4334', 'iPhone 5c', '2.4GHz'),
+    'wifi3|probe:0,1,50,3,45,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0020,htagg:1a,htmcs:000000ff,intwrk:02|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:0020,htagg:1a,htmcs:000000ff,txpow:1704|os:ios':
+        ('BCM4334', 'iPhone 5c', '2.4GHz'),
+
     'wifi3|probe:0,1,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0062,htagg:1a,htmcs:000000ff,intwrk:ff,extcap:00000804|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1603|os:ios':
         ('BCM4334', 'iPhone 5s', '5GHz'),
     'wifi3|probe:0,1,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0062,htagg:1a,htmcs:000000ff,intwrk:ff,extcap:00000804|assoc:0,1,33,36,48,45,70,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1603|os:ios':
@@ -333,15 +344,11 @@
     'wifi3|probe:0,1,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:0062,htagg:1a,htmcs:000000ff,intwrk:0f,extcap:00000004|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1706|os:ios':
         ('BCM4334', 'iPod Touch 5th gen', '2.4GHz'),
 
-    'wifi|probe:0,1,45,127,191,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:006f,vhtcap:0f805832|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(00904c,4),221(0050f2,2),htcap:006f,vhtcap:0f805832|oui:lg':
+    'wifi3|probe:0,1,3,45,127,191,221(001018,2),221(00904c,51),221(0050f2,8),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000080000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),cap:0011,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e001,extcap:0000000000000040|oui:lg':
         ('BCM4335', 'LG G2', '5GHz'),
-    'wifi|probe:0,1,45,127,191,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:00080000|assoc:0,1,33,36,45,127,191,221(001018,2),221(00904c,4),221(0050f2,2),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:00000000|oui:lg':
-        ('BCM4335', 'LG G2', '5GHz'),
-    'wifi|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:102d|assoc:0,1,33,36,48,50,45,127,221(001018,2),221(0050f2,2),htcap:102d|oui:lg':
+    'wifi3|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),221(0050f2,8),htcap:102d,htagg:17,htmcs:000000ff,extcap:0000080000000040|assoc:0,1,33,36,48,50,45,127,221(001018,2),221(0050f2,2),cap:0431,htcap:102d,htagg:17,htmcs:000000ff,txpow:11ff|oui:lg':
         ('BCM4335', 'LG G2', '2.4GHz'),
-    'wifi|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:102d|assoc:0,1,33,36,48,50,45,221(001018,2),221(0050f2,2),htcap:102d|oui:lg':
-        ('BCM4335', 'LG G2', '2.4GHz'),
-    'wifi|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:102d,htagg:17,htmcs:000000ff,extcap:00080000|assoc:0,1,33,36,50,45,221(001018,2),221(0050f2,2),htcap:102d,htagg:17,htmcs:000000ff|oui:lg':
+    'wifi3|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),221(0050f2,8),htcap:102d,htagg:17,htmcs:000000ff,extcap:0000080000000040|assoc:0,1,33,36,48,50,45,221(001018,2),221(0050f2,2),cap:0431,htcap:102d,htagg:17,htmcs:000000ff,txpow:11ff|oui:lg':
         ('BCM4335', 'LG G2', '2.4GHz'),
 
     'wifi3|probe:0,1,45,221(0050f2,8),191,127,107,221(506f9a,16),htcap:016e,htagg:03,htmcs:000000ff,vhtcap:31800120,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,intwrk:0f,extcap:000000800040|assoc:0,1,33,36,48,45,221(0050f2,2),191,127,cap:0111,htcap:016e,htagg:03,htmcs:000000ff,vhtcap:31805120,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:170d,extcap:00000a8201400040|oui:lg':
@@ -437,10 +444,16 @@
         ('QCA_WCN3360', 'Nexus 4', '5GHz'),
     'wifi3|probe:0,1,45,221(0050f2,8),191,221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,vhtcap:31811120,vhtrxmcs:01b2fffc,vhttxmcs:01b2fffc,wps:Nexus_4|assoc:0,1,48,45,221(0050f2,2),cap:0431,htcap:012c,htagg:03,htmcs:000000ff':
         ('QCA_WCN3360', 'Nexus 4', '5GHz'),
+    'wifi3|probe:0,1,45,221(0050f2,8),221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,wps:Nexus_4|assoc:0,1,48,45,221(0050f2,2),127,cap:0431,htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02':
+        ('QCA_WCN3360', 'Nexus 4', '5GHz'),
+    'wifi3|probe:0,1,45,221(0050f2,8),191,221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,vhtcap:31811120,vhtrxmcs:01b2fffc,vhttxmcs:01b2fffc,wps:Nexus_4|assoc:0,1,50,48,45,221(0050f2,2),cap:0431,htcap:012c,htagg:03,htmcs:000000ff':
+        ('QCA_WCN3360', 'Nexus 4', '5GHz'),
     'wifi3|probe:0,1,50,45,221(0050f2,8),191,221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,vhtcap:31811120,vhtrxmcs:01b2fffc,vhttxmcs:01b2fffc,wps:Nexus_4|assoc:0,1,50,48,45,221(0050f2,2),cap:0431,htcap:012c,htagg:03,htmcs:000000ff':
         ('QCA_WCN3360', 'Nexus 4', '2.4GHz'),
     'wifi3|probe:0,1,50,3,45,221(0050f2,8),221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,wps:Nexus_4|assoc:0,1,50,48,45,221(0050f2,2),cap:0431,htcap:012c,htagg:03,htmcs:000000ff':
         ('QCA_WCN3360', 'Nexus 4', '2.4GHz'),
+    'wifi3|probe:0,1,50,45,221(0050f2,8),htcap:012c,htagg:03,htmcs:000000ff|assoc:0,1,50,48,45,221(0050f2,2),127,cap:0431,htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02|oui:lg':
+        ('QCA_WCN3360', 'Nexus 4', '2.4GHz'),
 
     'wifi3|probe:0,1,45,127,191,221(001018,2),221(00904c,51),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),cap:0011,htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e003,extcap:0000000000000040|oui:lg':
         ('BCM4339', 'Nexus 5', '5GHz'),
@@ -645,13 +658,26 @@
     'wifi3|probe:0,1,50,3,45,127,107,221(506f9a,16),221(00904c,4),221(0050f2,8),221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,intwrk:0f,extcap:00080f8401400040|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),cap:0431,htcap:01ad,htagg:17,htmcs:0000ffff,txpow:1202|oui:murata':
         ('BCM4359', 'Samsung Galaxy Note 5', '2.4GHz'),
 
-    'wifi|probe:0,1,45,221(001018,2),221(00904c,51),htcap:0062|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:0062|oui:samsung':
+    'wifi3|probe:0,1,45,3,221(001018,2),221(00904c,51),htcap:000c,htagg:19,htmcs:000000ff|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:000c,htagg:19,htmcs:000000ff,txpow:0f09|oui:samsung':
+        ('', 'Samsung Galaxy S2+', '5GHz'),
+    'wifi3|probe:0,1,45,3,221(001018,2),221(00904c,51),htcap:000c,htagg:19,htmcs:000000ff|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:000c,htagg:19,htmcs:000000ff,txpow:0f09|oui:murata':
+        ('', 'Samsung Galaxy S2+', '5GHz'),
+    'wifi3|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:100c,htagg:19,htmcs:000000ff|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:100c,htagg:19,htmcs:000000ff,txpow:1209|oui:samsung':
+        ('', 'Samsung Galaxy S2+', '2.4GHz'),
+    'wifi3|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:100c,htagg:19,htmcs:000000ff|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:100c,htagg:19,htmcs:000000ff,txpow:1209|oui:murata':
+        ('', 'Samsung Galaxy S2+', '2.4GHz'),
+
+    'wifi3|probe:0,1,45,221(001018,2),221(00904c,51),htcap:0062,htagg:1a,htmcs:000000ff|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1409|oui:samsung':
         ('BCM4334', 'Samsung Galaxy S3', '5GHz'),
-    'wifi|probe:0,1,45,221(001018,2),221(00904c,51),htcap:0062|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:0062|oui:murata':
+    'wifi3|probe:0,1,45,221(001018,2),221(00904c,51),htcap:0062,htagg:1a,htmcs:000000ff|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1409|oui:murata':
         ('BCM4334', 'Samsung Galaxy S3', '5GHz'),
-    'wifi|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:1020|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:1020|oui:samsung':
+    'wifi3|probe:0,1,45,3,221(001018,2),221(00904c,51),htcap:0062,htagg:1a,htmcs:000000ff|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1409|oui:samsung':
+        ('BCM4334', 'Samsung Galaxy S3', '5GHz'),
+    'wifi3|probe:0,1,45,3,221(001018,2),221(00904c,51),htcap:0062,htagg:1a,htmcs:000000ff|assoc:0,1,33,36,48,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0011,htcap:0062,htagg:1a,htmcs:000000ff,txpow:1409|oui:murata':
+        ('BCM4334', 'Samsung Galaxy S3', '5GHz'),
+    'wifi3|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:1020,htagg:1a,htmcs:000000ff|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:1020,htagg:1a,htmcs:000000ff,txpow:1409|oui:samsung':
         ('BCM4334', 'Samsung Galaxy S3', '2.4GHz'),
-    'wifi|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:1020|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:1020|oui:murata':
+    'wifi3|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:1020,htagg:1a,htmcs:000000ff|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),cap:0431,htcap:1020,htagg:1a,htmcs:000000ff,txpow:1409|oui:murata':
         ('BCM4334', 'Samsung Galaxy S3', '2.4GHz'),
 
     'wifi3|probe:0,1,45,127,191,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000080000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(00904c,4),221(0050f2,2),cap:1111,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e001,extcap:0000000000000040|oui:samsung':
@@ -674,6 +700,10 @@
         ('BCM4335', 'Samsung Galaxy S4', '5GHz'),
     'wifi3|probe:0,1,45,127,191,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000080000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(00904c,4),221(0050f2,2),cap:0011,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e001,extcap:0000000000000040|oui:murata':
         ('BCM4335', 'Samsung Galaxy S4', '5GHz'),
+    'wifi3|probe:0,1,45,127,191,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000080000400040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(00904c,4),221(0050f2,2),cap:0011,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e001,extcap:0000000000400040|oui:samsung':
+        ('BCM4335', 'Samsung Galaxy S4', '5GHz'),
+    'wifi3|probe:0,1,45,127,191,221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000080000400040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(00904c,4),221(0050f2,2),cap:0011,htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f805832,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e001,extcap:0000000000400040|oui:murata':
+        ('BCM4335', 'Samsung Galaxy S4', '5GHz'),
     'wifi3|probe:0,1,50,3,45,127,107,221(506f9a,16),221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:102d,htagg:17,htmcs:000000ff,intwrk:0f,extcap:0000088000400040|assoc:0,1,33,36,48,50,45,127,107,221(001018,2),221(0050f2,2),cap:0431,htcap:102d,htagg:17,htmcs:000000ff,txpow:1201,intwrk:0f,extcap:000000800040|oui:samsung':
         ('BCM4335', 'Samsung Galaxy S4', '2.4GHz'),
     'wifi3|probe:0,1,50,3,45,127,107,221(506f9a,16),221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:102d,htagg:17,htmcs:000000ff,intwrk:0f,extcap:0000088000400040|assoc:0,1,33,36,48,50,45,127,107,221(001018,2),221(0050f2,2),cap:0431,htcap:102d,htagg:17,htmcs:000000ff,txpow:1201,intwrk:0f,extcap:000000800040|oui:murata':
diff --git a/wifi/iw.py b/wifi/iw.py
index a8ffdb4..b1d49b5 100644
--- a/wifi/iw.py
+++ b/wifi/iw.py
@@ -221,6 +221,16 @@
       return interface
 
 
+def find_all_interfaces_from_phy(phy):
+  interfaces = []
+  for interface_type in INTERFACE_TYPE:
+    pattern = re.compile(r'w%s[0-9]\w*\Z' % re.escape(interface_type))
+    interfaces.extend(interface for interface
+                      in dev_parsed()[phy]['interfaces']
+                      if pattern.match(interface))
+  return interfaces
+
+
 def find_interface_from_band(band, interface_type, interface_suffix):
   """Finds the name of an interface on a given band.
 
diff --git a/wifi/wifi.py b/wifi/wifi.py
index de8ced4..f57e09e 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -237,34 +237,47 @@
     raise utils.BinWifiException(
         'no wifi phy for band=%s channel=%s', band, channel)
 
-  client_interface = iw.find_interface_from_phy(
-      phy, iw.INTERFACE_TYPE.client, opt.interface_suffix)
-  if (client_interface is not None and
-      _is_wpa_supplicant_running(client_interface)):
-    # Wait up to ten seconds for client width and channel to be available (only
-    # relevant if client was started recently).
-    # TODO(rofrankel): Consider shortcutting this loop if wpa_cli shows status
-    # is SCANNING (and other values)?
-    utils.log('Client running on same band; finding its width and channel.')
-    for _ in xrange(50):
-      client_band = _get_wpa_band(client_interface)
-      client_width, client_channel = iw.find_width_and_channel(client_interface)
-      sys.stderr.write('.')
-      if None not in (client_band, client_width, client_channel):
-        band, width, channel = client_band, client_width, client_channel
-        utils.log('Using band=%s, channel=%s, width=%s MHz from client',
-                  band, channel, width)
-        break
-      time.sleep(0.2)
-    else:
-      utils.log("Couldn't find band, width, and channel used by client "
-                "(it may not be connected)")
-
   interface = iw.find_interface_from_phy(
       phy, iw.INTERFACE_TYPE.ap, opt.interface_suffix)
   if interface is None:
     raise utils.BinWifiException(
-        'no wifi interface for band=%s channel=%s', band, channel)
+        'no wifi interface found for band=%s channel=%s suffix=%s',
+        band, channel, opt.interface_suffix)
+
+  found_active_config = False
+  for other_interface in (set(iw.find_all_interfaces_from_phy(phy)) -
+                          set([interface])):
+    if _is_wpa_supplicant_running(other_interface):
+      get_band = _get_wpa_band
+    elif _is_hostapd_running(other_interface):
+      get_band = _get_hostapd_band
+    else:
+      continue
+
+    # Wait up to ten seconds for interface width and channel to be available
+    # (only relevant if hostapd/wpa_supplicant was started recently).
+    # TODO(rofrankel): Consider shortcutting this loop if wpa_cli shows status
+    # is SCANNING (and other values)?
+    utils.log('Interface %s running on same band; finding its width and '
+              'channel.', other_interface)
+    for _ in xrange(50):
+      active_band = get_band(other_interface)
+      active_width, active_channel = iw.find_width_and_channel(other_interface)
+
+      sys.stderr.write('.')
+      if None not in (active_band, active_width, active_channel):
+        band, width, channel = active_band, active_width, active_channel
+        utils.log('Using band=%s, channel=%s, width=%s MHz from interface %s',
+                  band, channel, width, other_interface)
+        found_active_config = True
+        break
+      time.sleep(0.2)
+    else:
+      utils.log("Couldn't find band, width, and channel used by interface %s "
+                "(it may not be connected)", other_interface)
+
+    if found_active_config:
+      break
 
   utils.log('interface: %s', interface)
   utils.log('Configuring cfg80211 wifi.')
@@ -495,6 +508,17 @@
     return []
 
 
+def _get_hostapd_band(interface):
+  for line in utils.subprocess_lines(
+      ('hostapd_cli', '-i', interface, 'status')):
+    tokens = line.split('=')
+    if tokens and tokens[0] == 'freq':
+      try:
+        return {'5': '5', '2': '2.4'}[tokens[1][0]]
+      except (IndexError, KeyError):
+        return None
+
+
 def _start_hostapd(interface, config_filename, band, ssid):
   """Starts a babysat hostapd.
 
@@ -579,7 +603,7 @@
     if tokens and tokens[0] == 'freq':
       try:
         return {'5': '5', '2': '2.4'}[tokens[1][0]]
-      except KeyError:
+      except (IndexError, KeyError):
         return None