/bin/wifi: Save options per-interface rather than per-band.
This adds support for persisting options for interfaces with suffixes
(currently missing, due to an oversight). It also simplifies the case
for dual-band radios; previously, there was code specifically to
handle the case in which options were persisted for both bands, and
the wrong ones got restored.
BUG=33755395
Change-Id: I5fdb70fad5295d163e372199ffecefd498aee2c2
diff --git a/wifi/iw.py b/wifi/iw.py
index c0bbf57..f16c50b 100644
--- a/wifi/iw.py
+++ b/wifi/iw.py
@@ -267,10 +267,10 @@
def find_all_interfaces_from_band(band, interface_type=None):
- """Finds the names of all interface on a given band.
+ """Finds the names of all interfaces on a given band.
Args:
- band: The band for which you want the interface.
+ band: The band for which you want the interface(s).
interface_type: An INTERFACE_TYPE value (optional).
Returns:
@@ -283,6 +283,32 @@
return find_all_interfaces_from_phy(phy, interface_type)
+def find_interfaces_from_band_and_suffix(band, suffix, interface_type=None):
+ """Finds the names of interfaces on a given band.
+
+ Args:
+ band: The band for which you want the interface(s).
+ suffix: The interface suffix. 'ALL' is a special value that matches all
+ suffixes.
+ interface_type: An INTERFACE_TYPE value (optional).
+
+ Returns:
+ A list of all interfaces found.
+ """
+ interfaces = set()
+ if suffix == 'ALL':
+ interfaces = find_all_interfaces_from_band(band, interface_type)
+ else:
+ interface_types = interface_type or (INTERFACE_TYPE.ap,
+ INTERFACE_TYPE.client)
+ for ifc_type in interface_types:
+ interface = find_interface_from_band(band, ifc_type, suffix)
+ if interface:
+ interfaces.add(interface)
+
+ return interfaces
+
+
def find_width_and_channel(interface):
"""Finds the width and channel being used by a given interface.
diff --git a/wifi/iw_test.py b/wifi/iw_test.py
index 2293954..b7ebb3a 100755
--- a/wifi/iw_test.py
+++ b/wifi/iw_test.py
@@ -555,6 +555,28 @@
@wvtest.wvtest
+def find_interfaces_from_band_and_suffix_test():
+ """Test find_interfaces_from_band_and_suffix."""
+ wvtest.WVPASSEQ(set(['wlan0', 'wlan0_portal', 'wcli0']),
+ iw.find_interfaces_from_band_and_suffix('2.4', 'ALL'))
+ wvtest.WVPASSEQ(set(['wlan0', 'wcli0']),
+ iw.find_interfaces_from_band_and_suffix('2.4', ''))
+ wvtest.WVPASSEQ(set(['wlan0_portal']),
+ iw.find_interfaces_from_band_and_suffix('2.4', '_portal'))
+ wvtest.WVPASSEQ(set([]),
+ iw.find_interfaces_from_band_and_suffix('2.4', 'fake_suffix'))
+
+ wvtest.WVPASSEQ(set(['wlan0', 'wlan0_portal']),
+ iw.find_interfaces_from_band_and_suffix('2.4', 'ALL',
+ iw.INTERFACE_TYPE.ap))
+ wvtest.WVPASSEQ(set(['wcli0']),
+ iw.find_interfaces_from_band_and_suffix(
+ '2.4', 'ALL', iw.INTERFACE_TYPE.client))
+ wvtest.WVPASSEQ(set(['wlan1', 'wlan1_portal']),
+ iw.find_interfaces_from_band_and_suffix('5', 'ALL'))
+
+
+@wvtest.wvtest
def info_parsed_test():
wvtest.WVPASSEQ({
'wdev': '0x3',
diff --git a/wifi/persist.py b/wifi/persist.py
index 827c2a1..3290698 100644
--- a/wifi/persist.py
+++ b/wifi/persist.py
@@ -8,8 +8,11 @@
import utils
+# TODO(rofrankel): Figure out the right way to delete old-style persisted
+# options (e.g. /config/wifi/hostapd.opts.5).
-def save_options(program, band, argv, tmp=False):
+
+def save_options(program, interface, argv, tmp=False):
"""Saves program options.
Persistence options are stripped before saving to prevent rewriting identical
@@ -17,7 +20,7 @@
Args:
program: The program for which to save options.
- band: The band for which to save options.
+ interface: The interface for which to save options.
argv: The options to save.
tmp: Whether to save options to /tmp or _CONFIG_DIR.
"""
@@ -35,16 +38,17 @@
os.environ['WIFI_CLIENT_PSK'])
utils.atomic_write(
- utils.get_filename(program, utils.FILENAME_KIND.options, band, tmp=tmp),
+ utils.get_filename(program, utils.FILENAME_KIND.options, interface,
+ tmp=tmp),
repr(to_save))
-def load_options(program, band, tmp):
+def load_options(program, interface, tmp):
"""Loads program options, if any have been saved.
Args:
program: The program for which to load options.
- band: The band for which to load options.
+ interface: The interface for which to load options.
tmp: Whether to load options from /tmp (i.e. what is currently running) or
_CONFIG_DIR (the options from last time --persist was set).
@@ -52,7 +56,7 @@
The stored options (which can be passed to wifi._run), or None if the file
cannot be opened.
"""
- filename = utils.get_filename(program, utils.FILENAME_KIND.options, band,
+ filename = utils.get_filename(program, utils.FILENAME_KIND.options, interface,
tmp=tmp)
try:
with open(filename) as options_file:
@@ -65,26 +69,26 @@
raise
-def delete_options(program, band):
+def delete_options(program, interface):
"""Deletes persisted program options from _CONFIG_DIR.
Args:
program: The program for which to delete options.
- band: The band for which to delete options.
+ interface: The interface for which to delete options.
Returns:
Whether deletion succeeded.
"""
- filename = utils.get_filename(program, utils.FILENAME_KIND.options, band)
+ filename = utils.get_filename(program, utils.FILENAME_KIND.options, interface)
if os.path.exists(filename):
try:
os.remove(filename)
- utils.log('Removed persisted options for %s GHz %s.', band, program)
+ utils.log('Removed persisted options for %s %s.', interface, program)
except OSError:
- utils.log('Failed to remove persisted options for %s GHz %s.',
- band, program)
+ utils.log('Failed to remove persisted options for %s %s.',
+ interface, program)
return False
else:
- utils.log('No persisted options to remove for %s GHz %s.', band, program)
+ utils.log('No persisted options to remove for %s %s.', interface, program)
return True
diff --git a/wifi/wifi.py b/wifi/wifi.py
index 3773f03..8c34774 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -401,7 +401,7 @@
for interface in interfaces:
if _stop_hostapd(interface):
if opt.persist:
- persist.delete_options('hostapd', band)
+ persist.delete_options('hostapd', interface)
else:
utils.log('Failed to stop hostapd on interface %s', interface)
success = False
@@ -410,29 +410,29 @@
@iw.requires_iw
-def _restore_wifi(band, program):
+def _restore_wifi(interface, program):
"""Restore a program from persisted settings.
Args:
- band: The band on which to restore program.
+ interface: The interface on which to restore program.
program: The program to restore (wpa_supplicant or hostapd).
Returns:
- Whether whether restoring succeeded, but may die.
+ Whether restoring succeeded.
"""
- argv = persist.load_options(program, band, False)
+ argv = persist.load_options(program, interface, False)
if argv is None:
- utils.log('No persisted options for %s GHz %s, not restoring',
- band, program)
+ utils.log('No persisted options for %s %s, not restoring',
+ interface, program)
return False
- utils.log('Loaded persisted options for %s GHz %s', band, program)
+ utils.log('Loaded persisted options for %s %s', interface, program)
if _run(argv):
- utils.log('Restored %s for %s GHz', program, band)
+ utils.log('Restored %s for %s', program, interface)
return True
- utils.log('Failed to restore %s for %s GHz', program, band)
+ utils.log('Failed to restore %s for %s', program, interface)
return False
@@ -449,11 +449,19 @@
"""
# If both bands are specified, restore 5 GHz first so that STAs are more
# likely to join it.
+ restored = set()
for band in sorted(opt.band.split(),
reverse=not experiment.enabled('WifiReverseBandsteering')):
- _restore_wifi(band, 'wpa_supplicant')
- _restore_wifi(band, 'hostapd')
-
+ client_interface = iw.find_interface_from_band(band,
+ iw.INTERFACE_TYPE.client,
+ opt.interface_suffix)
+ ap_interface = iw.find_interface_from_band(band, iw.INTERFACE_TYPE.ap,
+ opt.interface_suffix)
+ for interface, program in ((client_interface, 'wpa_supplicant'),
+ (ap_interface, 'hostapd')):
+ if interface and interface not in restored:
+ restored.add(interface)
+ _restore_wifi(interface, program)
return True
@@ -833,13 +841,14 @@
return True
-def _restart_hostapd(band):
+def _restart_hostapd(interface, *overrides):
"""Restart hostapd from previous options.
Only used by _set_wpa_supplicant_config, to restart hostapd after stopping it.
Args:
- band: The band on which to restart hostapd.
+ interface: The interface on which to restart hostapd.
+ *overrides: A list of options to override the pre-existing ones.
Returns:
Whether hostapd was successfully restarted.
@@ -847,7 +856,7 @@
Raises:
BinWifiException: If reading previous settings fails.
"""
- argv = persist.load_options('hostapd', band, True)
+ argv = persist.load_options('hostapd', interface, True) + list(overrides)
if argv is None:
raise utils.BinWifiException('Failed to read previous hostapd config')
@@ -929,7 +938,7 @@
'details.')
if restart_hostapd:
- _restart_hostapd(band)
+ _restart_hostapd(ap_interface)
return True
@@ -1023,15 +1032,8 @@
if band == '5' and quantenna.stop_client_wifi(opt):
continue
- interfaces = []
- if opt.interface_suffix == 'ALL':
- interfaces = iw.find_all_interfaces_from_band(
- band, iw.INTERFACE_TYPE.client)
- else:
- interface = iw.find_interface_from_band(
- band, iw.INTERFACE_TYPE.client, opt.interface_suffix)
- if interface:
- interfaces = [interface]
+ interfaces = iw.find_interfaces_from_band_and_suffix(
+ band, opt.interface_suffix, iw.INTERFACE_TYPE.client)
if not interfaces:
utils.log('No client interfaces for %s GHz; nothing to stop', band)
continue
@@ -1039,7 +1041,7 @@
for interface in interfaces:
if _stop_wpa_supplicant(interface):
if opt.persist:
- persist.delete_options('wpa_supplicant', band)
+ persist.delete_options('wpa_supplicant', interface)
else:
utils.log('Failed to stop wpa_supplicant on interface %s', interface)
success = False
@@ -1125,14 +1127,19 @@
if success:
if command in ('set', 'setclient'):
- program = 'hostapd' if command == 'set' else 'wpa_supplicant'
+ if command == 'set':
+ program = 'hostapd'
+ interface_type = iw.INTERFACE_TYPE.ap
+ else:
+ program = 'wpa_supplicant'
+ interface_type = iw.INTERFACE_TYPE.client
+ interface = iw.find_interface_from_band(opt.band, interface_type,
+ opt.interface_suffix)
if opt.persist:
- phy = iw.find_phy(opt.band, opt.channel)
- for band in iw.phy_bands(phy):
- if band != opt.band:
- persist.delete_options(program, band)
- persist.save_options(program, opt.band, argv)
- persist.save_options(program, opt.band, argv, tmp=True)
+ # Save in /config.
+ persist.save_options(program, interface, argv, False)
+ # Save in /tmp.
+ persist.save_options(program, interface, argv, True)
return success