conman: Avoid losing track of wpa_supplicant link.
Under circumstances not yet fully understood, conman may mistakenly
think wpa_supplicant is down and never discover the mistake, causing it
to remove routes for that interface. This adds a regular check for the
link state to make sure this doesn't happen.
BUG=31261343
Change-Id: I3fe8cd905ef44f605d94952ef34685f1ca5fb862
diff --git a/conman/interface.py b/conman/interface.py
index 66855dc..b741555 100755
--- a/conman/interface.py
+++ b/conman/interface.py
@@ -488,9 +488,7 @@
"""
status = {}
- if self._wpa_control and self._wpa_control.attached:
- logging.debug('%s ctrl_iface_path %s',
- self, self._wpa_control.ctrl_iface_path)
+ if self.attached():
lines = []
try:
lines = self._wpa_control.request('STATUS').splitlines()
@@ -504,6 +502,7 @@
k, v = line.strip().split('=', 1)
status[k] = v
+ logging.debug('wpa_status is %r', status)
return status
def get_wpa_control(self, socket):
@@ -525,6 +524,9 @@
self.wpa_supplicant = False
return
+ # b/31261343: Make sure we didn't miss wpa_supplicant being up.
+ self.wpa_supplicant = self.wpa_status().get('wpa_state', '') == 'COMPLETED'
+
while self._wpa_control.pending():
match = self.WPA_EVENT_RE.match(self._wpa_control.recv())
if match:
diff --git a/conman/interface_test.py b/conman/interface_test.py
index f9c1e6d..14fb795 100755
--- a/conman/interface_test.py
+++ b/conman/interface_test.py
@@ -175,7 +175,6 @@
def generic_wifi_test(w, wpa_path):
# Not currently connected.
- # w.start_wpa_supplicant_testonly(wpa_path)
subprocess.wifi.WPA_PATH = wpa_path
w.attach_wpa_control(wpa_path)
wvtest.WVFAIL(w.wpa_supplicant)
@@ -330,5 +329,62 @@
shutil.rmtree(interface.CWMP_PATH)
+@wvtest.wvtest
+def b31261343_test():
+ """Test Wifi."""
+ w = Wifi('wcli0', '21')
+ w.initialize()
+
+ try:
+ wpa_path = tempfile.mkdtemp()
+ conman_path = tempfile.mkdtemp()
+ subprocess.set_conman_paths(conman_path, None)
+ subprocess.mock('wifi', 'interfaces',
+ subprocess.wifi.MockInterface(phynum='0', bands=['5'],
+ driver='cfg80211'))
+ subprocess.wifi.WPA_PATH = wpa_path
+
+ w.attach_wpa_control(wpa_path)
+ wvtest.WVFAIL(w.wpa_supplicant)
+
+ # Set up.
+ ssid = 'my=ssid'
+ psk = 'passphrase'
+ subprocess.mock('wifi', 'remote_ap', ssid=ssid, psk=psk, band='5',
+ bssid='00:00:00:00:00:00', connection_check_result='succeed')
+ subprocess.check_call(['wifi', 'setclient', '--ssid', ssid, '--band', '5'],
+ env={'WIFI_CLIENT_PSK': psk})
+
+ w.set_gateway_ip('192.168.1.1')
+ w.set_subnet('192.168.1.0/24')
+ wvtest.WVFAIL(w.wpa_supplicant)
+ w.attach_wpa_control(wpa_path)
+ w.handle_wpa_events()
+
+ def check_working():
+ w.update_routes(True)
+ wvtest.WVPASS(w.wpa_supplicant)
+ wvtest.WVPASS('default' in w.current_routes())
+
+ def check_broken():
+ w.update_routes(True)
+ wvtest.WVFAIL(w.wpa_supplicant)
+ wvtest.WVFAIL('default' in w.current_routes())
+
+ check_working()
+
+ # This is the buggy state.
+ w.wpa_supplicant = False
+ check_broken()
+
+ # Should fix itself when we next run handle_wpa_events.
+ w.handle_wpa_events()
+ check_working()
+
+ finally:
+ shutil.rmtree(wpa_path)
+ shutil.rmtree(conman_path)
+
+
if __name__ == '__main__':
wvtest.wvtest_main()