Merge "conman:  Re-use successful provisioning APs."
diff --git a/base/time.cc b/base/time.cc
index d1427c3..2672023 100644
--- a/base/time.cc
+++ b/base/time.cc
@@ -65,7 +65,7 @@
 }
 
 // Make sure someone calls it so that it gets initialized
-static uint32 ignore = StartTime();
+static uint32 __attribute__((used)) ignore = StartTime();
 
 uint32 TimeAfter(int32 elapsed) {
   ASSERT(elapsed >= 0);
diff --git a/cmds/test-mmap.sh b/cmds/test-mmap.sh
index 85b3004..32710d9 100755
--- a/cmds/test-mmap.sh
+++ b/cmds/test-mmap.sh
@@ -18,7 +18,14 @@
     $PREFIX ../host-mmap $ARGS < INPUT > GOT 2>&1
     status=$?
     if [ -n "$PREFIX" ]; then
-      sleep .5      # script mysteriously delays output
+      # /usr/bin/script mysteriously delays output (child writes cached?)
+      # sleep up to 4 seconds waiting for the output
+      for n in $(seq 1 40); do
+        if [ -s GOT ]; then
+          break
+        fi
+        sleep .1
+      done
     fi
     if [ "$status" != "$EXIT" ]; then
       echo "exit code: expected '$EXIT', got '$status'"
diff --git a/speedtest/utils.cc b/speedtest/utils.cc
index 580b54b..8144174 100644
--- a/speedtest/utils.cc
+++ b/speedtest/utils.cc
@@ -67,7 +67,7 @@
     return false;
   }
   std::istringstream n(str);
-  return n >> *result;
+  return !(n >> *result).fail();
 }
 
 // Trim from start in place
diff --git a/sysmgr/peripheral/fancontrol.cc b/sysmgr/peripheral/fancontrol.cc
index a19afa9..8e81fe1 100644
--- a/sysmgr/peripheral/fancontrol.cc
+++ b/sysmgr/peripheral/fancontrol.cc
@@ -226,6 +226,16 @@
                           temp_overheat : 97,
                         };
 
+const FanControlParams FanControl::kGFLT300FanCtrlSocDefaults = {
+                          temp_setpt    : 0,  /* No fan */
+                          temp_max      : 0,
+                          temp_step     : 0,
+                          duty_cycle_min: 0,
+                          duty_cycle_max: 0,
+                          pwm_step      : 0,
+                          temp_overheat : 97,
+                        };
+
 FanControl::~FanControl() {
   Terminate();
 }
@@ -310,6 +320,9 @@
     case BRUNO_GFLT110:
       pfan_ctrl_params_[BRUNO_SOC] = kGFLT110FanCtrlSocDefaults;
       break;
+    case BRUNO_GFLT300:
+      pfan_ctrl_params_[BRUNO_SOC] = kGFLT300FanCtrlSocDefaults;
+      break;
     case BRUNO_UNKNOWN:
       LOG(LS_ERROR) << "Invalid platform type, ignore ... " << platform_;
       break;
diff --git a/sysmgr/peripheral/fancontrol.h b/sysmgr/peripheral/fancontrol.h
index 2e552e3..06e8499 100644
--- a/sysmgr/peripheral/fancontrol.h
+++ b/sysmgr/peripheral/fancontrol.h
@@ -81,6 +81,7 @@
   static const FanControlParams kGFHD254FanCtrlAux1Defaults;
 
   static const FanControlParams kGFLT110FanCtrlSocDefaults;
+  static const FanControlParams kGFLT300FanCtrlSocDefaults;
 
   explicit FanControl(Platform *platform)
       : state_(OFF),
diff --git a/sysmgr/peripheral/platform.cc b/sysmgr/peripheral/platform.cc
index 23572a0..ba239fd 100644
--- a/sysmgr/peripheral/platform.cc
+++ b/sysmgr/peripheral/platform.cc
@@ -20,6 +20,7 @@
   Platform("GFLT110", BRUNO_GFLT110, false, false, false),
   Platform("GFLT120", BRUNO_GFLT110, false, false, false),
   Platform("GFHD254", BRUNO_GFHD254, false, true, true),
+  Platform("GFLT300", BRUNO_GFLT300, false, false, false),
   Platform("UNKNOWN PLATFORM", BRUNO_UNKNOWN, false, false,  false),
 };
 
diff --git a/sysmgr/peripheral/platform.h b/sysmgr/peripheral/platform.h
index 80e0a74..91a5925 100644
--- a/sysmgr/peripheral/platform.h
+++ b/sysmgr/peripheral/platform.h
@@ -26,6 +26,7 @@
   BRUNO_GFHD200,          /* Camaro */
   BRUNO_GFLT110,          /* Fiber Jack */
   BRUNO_GFHD254,          /* Lockdown */
+  BRUNO_GFLT300,          /* Go-Long FiberJack */
   BRUNO_UNKNOWN
 };
 
diff --git a/waveguide/waveguide.py b/waveguide/waveguide.py
index db2f9ed..cbc9fe8 100755
--- a/waveguide/waveguide.py
+++ b/waveguide/waveguide.py
@@ -783,7 +783,7 @@
         a = wgdata.Assoc(mac=mac, rssi=rssi, last_seen=last_seen, can5G=can5G)
         if mac not in self.assoc_list:
           self.Debug('Added: %r', a)
-          self.wifiblaster_controller.Measure(self.vdevname, mac)
+          self.wifiblaster_controller.MeasureOnAssociation(self.vdevname, mac)
         assoc_list[mac] = a
 
     for line in stdout.split('\n'):
@@ -904,16 +904,18 @@
 
   - Scheduling parameters
 
-    wifiblaster.enable      Enable WiFi performance measurement.
-    wifiblaster.interval    Average time between automated measurements in
-                            seconds, or 0 to disable automated measurements.
-    wifiblaster.measureall  Unix time at which to measure all clients.
+    wifiblaster.enable         Enable WiFi performance measurement.
+    wifiblaster.interval       Average time between automated measurements in
+                               seconds, or 0 to disable automated measurements.
+    wifiblaster.measureall     Unix time at which to measure all clients.
+    wifiblaster.onassociation  Enable WiFi performance measurement after clients
+                               associate.
 
   - Measurement parameters
 
-    wifiblaster.duration    Measurement duration in seconds.
-    wifiblaster.fraction    Number of samples per measurement.
-    wifiblaster.size        Packet size in bytes.
+    wifiblaster.duration       Measurement duration in seconds.
+    wifiblaster.fraction       Number of samples per measurement.
+    wifiblaster.size           Packet size in bytes.
   """
 
   def __init__(self, managers, basedir):
@@ -985,6 +987,12 @@
                     '-f', str(fraction), '-s', str(size),
                     helpers.DecodeMAC(client)])
 
+  def MeasureOnAssociation(self, interface, client):
+    """Measures the performance of a client after association."""
+    onassociation = self._ReadParameter('onassociation', self._StrToBool)
+    if onassociation:
+      self.Measure(interface, client)
+
   def Poll(self, now):
     """Polls the state machine."""
 
diff --git a/waveguide/wifiblaster_controller_test.py b/waveguide/wifiblaster_controller_test.py
index 04e71f8..6b562b1 100755
--- a/waveguide/wifiblaster_controller_test.py
+++ b/waveguide/wifiblaster_controller_test.py
@@ -208,6 +208,15 @@
       wvtest.WVPASSEQ(CountRuns(), 1)
       wc.Poll(501)
       wvtest.WVPASSEQ(CountRuns(), 0)
+
+      # Measure on association only if enabled.
+      wc.MeasureOnAssociation(manager.vdevname,
+                              manager.GetState().assoc[0].mac)
+      wvtest.WVPASSEQ(CountRuns(), 0)
+      WriteConfig('onassociation', 'True')
+      wc.MeasureOnAssociation(manager.vdevname,
+                              manager.GetState().assoc[0].mac)
+      wvtest.WVPASSEQ(CountRuns(), 1)
   finally:
     time.time = oldtime
     shutil.rmtree(d)
diff --git a/wifi/configs.py b/wifi/configs.py
index 7518872..11867b2 100644
--- a/wifi/configs.py
+++ b/wifi/configs.py
@@ -77,6 +77,7 @@
 {require_ht}
 {require_vht}
 {hidden}
+{ap_isolate}
 
 ht_capab={ht20}{ht40}{guard_interval}{ht_rxstbc}
 {vht_settings}
@@ -275,6 +276,7 @@
   enable_wmm = 'wmm_enabled=1' if opt.enable_wmm else ''
   hidden = 'ignore_broadcast_ssid=1' if opt.hidden_mode else ''
   bridge = 'bridge=%s' % opt.bridge if opt.bridge else ''
+  ap_isolate = 'ap_isolate=1' if opt.client_isolation else ''
   hostapd_conf_parts = [_HOSTCONF_TPL.format(
       interface=interface, band=band, channel=channel, width=width,
       protocols=protocols, hostapd_band=hostapd_band,
@@ -282,7 +284,8 @@
       require_ht=require_ht, require_vht=require_vht, ht20=ht20, ht40=ht40,
       ht_rxstbc=ht_rxstbc, vht_settings=vht_settings,
       guard_interval=guard_interval, enable_wmm=enable_wmm, hidden=hidden,
-      auth_algs=auth_algs, bridge=bridge, ssid=utils.sanitize_ssid(opt.ssid))]
+      ap_isolate=ap_isolate, auth_algs=auth_algs, bridge=bridge,
+      ssid=utils.sanitize_ssid(opt.ssid))]
 
   if opt.encryption != 'NONE':
     hostapd_conf_parts.append(_HOSTCONF_WPA_TPL.format(
diff --git a/wifi/configs_test.py b/wifi/configs_test.py
index 3956642..77773ce 100755
--- a/wifi/configs_test.py
+++ b/wifi/configs_test.py
@@ -309,6 +309,7 @@
 
 
 
+
 ht_capab=[HT20][RX-STBC1]
 
 """
@@ -331,6 +332,7 @@
 
 
 
+
 ht_capab=[HT20][RX-STBC1]
 
 """
@@ -363,6 +365,7 @@
     self.yottasecond_timeouts = False
     self.persist = False
     self.interface_suffix = ''
+    self.client_isolation = False
 
 
 # pylint: disable=protected-access
diff --git a/wifi/wifi.py b/wifi/wifi.py
index bd796a1..9ba8b31 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -40,6 +40,7 @@
 bssid=                            BSSID to use []
 e,encryption=                     Encryption type to use (WPA_PSK_AES, WPA2_PSK_AES, WPA12_PSK_AES, WPA_PSK_TKIP, WPA2_PSK_TKIP, WPA12_PSK_TKIP, WEP, or NONE) [WPA2_PSK_AES]
 f,force-restart                   Force restart even if already running with these options
+C,client-isolation                Enable client isolation, preventing bridging of frames between associated stations.
 H,hidden-mode                     Enable hidden mode (disable SSID advertisements)
 M,enable-wmm                      Enable wmm extensions (needed for block acks)
 G,short-guard-interval            Enable short guard interval