Merge "conman: Set WLAN retry delay properly after a new WLAN config."
diff --git a/conman/connection_manager.py b/conman/connection_manager.py
index b3e11e6..c9a4db1 100755
--- a/conman/connection_manager.py
+++ b/conman/connection_manager.py
@@ -76,11 +76,13 @@
WIFI_SETCLIENT = ['wifi', 'setclient', '--persist']
WIFI_STOPCLIENT = ['wifi', 'stopclient', '--persist']
- def __init__(self, band, wifi, command_lines):
+ def __init__(self, band, wifi, command_lines, retry_s):
self.band = band
self.wifi = wifi
self.logger = self.wifi.logger.getChild(self.band)
self.command = command_lines.splitlines()
+ self.retry_s = retry_s
+ self.try_after = 0
self.access_point_up = False
self.ssid = None
self.passphrase = None
@@ -155,6 +157,11 @@
self.logger.info('WifiNo2GClient enabled; not starting 2.4 GHz client.')
return
+ now = _gettime()
+ if now <= self.try_after:
+ self.logger.debug('Not retrying for another %.2fs', self.try_after - now)
+ return
+
up = self.client_up
if up:
self.logger.debug('Wifi client already started on %s GHz', self.band)
@@ -166,6 +173,9 @@
if self._actually_start_client() and self.client_up:
self.wifi.status.connected_to_wlan = True
self.logger.info('Started wifi client on %s GHz', self.band)
+ self.try_after = now
+ else:
+ self.try_after = now + self.retry_s
def _actually_start_client(self):
"""Actually run wifi setclient.
@@ -348,7 +358,6 @@
self._stop_wifi(wifi.bands[0], True, True)
self._interface_update_counter = 0
- self._try_wlan_after = {'5': 0, '2.4': 0}
for wifi in self.wifi:
ratchet_name = '%s provisioning' % wifi.name
@@ -524,18 +533,16 @@
# case 5 is unavailable for some reason.
for band in wifi.bands:
wlan_configuration = self._wlan_configuration.get(band, None)
- if wlan_configuration and _gettime() >= self._try_wlan_after[band]:
+ if wlan_configuration:
logger.info('Trying to join WLAN on %s.', wifi.name)
wlan_configuration.start_client()
if self._connected_to_wlan(wifi):
logger.info('Joined WLAN on %s.', wifi.name)
wifi.status.connected_to_wlan = True
- self._try_wlan_after[band] = 0
break
else:
logger.error('Failed to connect to WLAN on %s.', wifi.name)
wifi.status.connected_to_wlan = False
- self._try_wlan_after[band] = _gettime() + self._wlan_retry_s
else:
# If we are aren't on the WLAN, can ping the ACS, and haven't gotten a
# new WLAN configuration yet, there are two possibilities:
@@ -559,9 +566,8 @@
if self._wlan_configuration:
logger.info('ACS has not updated WLAN configuration; will retry '
' with old config.')
- for w in self.wifi:
- for b in w.bands:
- self._try_wlan_after[b] = now
+ for wlan_configuration in self._wlan_configuration.itervalues():
+ wlan_configuration.try_after = now
continue
# We don't want to want to log this spammily, so do exponential
# backoff.
@@ -716,7 +722,8 @@
wifi = self.wifi_for_band(band)
if wifi:
self._update_wlan_configuration(
- self.WLANConfiguration(band, wifi, contents))
+ self.WLANConfiguration(band, wifi, contents,
+ self._wlan_retry_s))
elif filename.startswith(self.ACCESS_POINT_FILE_PREFIX):
match = re.match(self.ACCESS_POINT_FILE_REGEXP, filename)
if match:
diff --git a/conman/connection_manager_test.py b/conman/connection_manager_test.py
index e9807cd..bec59f7 100755
--- a/conman/connection_manager_test.py
+++ b/conman/connection_manager_test.py
@@ -108,7 +108,7 @@
'--bridge=br0', '-s', 'my ssid=1', '--interface-suffix', '_suffix',
])
config = connection_manager.WLANConfiguration(
- '5', interface_test.Wifi('wcli0', 20), cmd)
+ '5', interface_test.Wifi('wcli0', 20), cmd, 10)
wvtest.WVPASSEQ('my ssid=1', config.ssid)
wvtest.WVPASSEQ('abcdWIFI_PSK=qwer', config.passphrase)
@@ -270,20 +270,21 @@
# Test that missing directories are created by ConnectionManager.
shutil.rmtree(tmp_dir)
- c = ConnectionManager(tmp_dir=tmp_dir,
- config_dir=config_dir,
- moca_tmp_dir=moca_tmp_dir,
- run_duration_s=run_duration_s,
- interface_update_period=interface_update_period,
- wlan_retry_s=0,
- wifi_scan_period_s=wifi_scan_period_s,
- associate_wait_s=associate_wait_s,
- dhcp_wait_s=dhcp_wait_s,
- acs_connection_check_wait_s=acs_cc_wait_s,
- acs_start_wait_s=acs_start_wait_s,
- acs_finish_wait_s=acs_finish_wait_s,
- bssid_cycle_length_s=1,
- **cm_kwargs)
+ kwargs = dict(tmp_dir=tmp_dir,
+ config_dir=config_dir,
+ moca_tmp_dir=moca_tmp_dir,
+ run_duration_s=run_duration_s,
+ interface_update_period=interface_update_period,
+ wlan_retry_s=0,
+ wifi_scan_period_s=wifi_scan_period_s,
+ associate_wait_s=associate_wait_s,
+ dhcp_wait_s=dhcp_wait_s,
+ acs_connection_check_wait_s=acs_cc_wait_s,
+ acs_start_wait_s=acs_start_wait_s,
+ acs_finish_wait_s=acs_finish_wait_s,
+ bssid_cycle_length_s=1)
+ kwargs.update(cm_kwargs)
+ c = ConnectionManager(**kwargs)
f(c)
except Exception:
@@ -680,7 +681,7 @@
wvtest.WVPASSEQ(last_bss_info.ssid, 's3')
wvtest.WVPASSEQ(last_bss_info.bssid, 'ff:ee:dd:cc:bb:aa')
# Attempt to interrupt provisioning, make sure it doesn't work.
- c._try_wlan_after[band] = 0
+ c._wlan_configuration[band].try_after = 0
# Second iteration: check that we try s3 again since there's no gateway yet.
c.run_once()
last_bss_info = c.wifi_for_band(band).last_attempted_bss_info
@@ -1103,5 +1104,20 @@
wvtest.WVFAIL(c.client_up('2.4'))
+@test_common.wvtest
+@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897,
+ wlan_configs={'5': False}, wlan_retry_s=30,
+ __test_interfaces_already_up=[])
+def test_regression_b29364958(c):
+ def count_setclient_calls():
+ return len([1 for cmd, _ in subprocess.CALL_HISTORY
+ if 'wifi' in cmd and 'setclient' in cmd])
+
+ wvtest.WVPASSEQ(1, count_setclient_calls())
+ for _ in range(10):
+ c.run_once()
+ wvtest.WVPASSEQ(1, count_setclient_calls())
+
+
if __name__ == '__main__':
wvtest.wvtest_main()
diff --git a/conman/test/fake_python/subprocess/__init__.py b/conman/test/fake_python/subprocess/__init__.py
index 3d73d4d..ff8ad0a 100644
--- a/conman/test/fake_python/subprocess/__init__.py
+++ b/conman/test/fake_python/subprocess/__init__.py
@@ -11,6 +11,8 @@
logger.setLevel(logging.DEBUG)
+CALL_HISTORY = []
+
# Values are only for when the module name does not match the command name.
_COMMAND_NAMES = {
'connection_check': None,
@@ -50,6 +52,8 @@
def _call(command, **kwargs):
"""Fake subprocess call."""
+ CALL_HISTORY.append((command, kwargs))
+
if type(command) not in (tuple, list):
raise Exception('Fake subprocess.call only supports list/tuple commands, '
'got: %s', command)
@@ -104,7 +108,9 @@
def reset():
- """Reset any module-level state."""
+ """Reset all state."""
+ global CALL_HISTORY
+ CALL_HISTORY = []
for command in _COMMANDS.itervalues():
if isinstance(command, types.ModuleType):
reload(command)