bin/wifi: avoid channel conflicts starting APs.
hostapd will fail to start with an uninformative error, "Failed to set
beacon parameters," if you try to start a VAP with it and there is an
existing AP configured on a different channel that uses the same radio.
Work around this by letting the first channel setting win. A later CL
will provide a way for us to actually change channel in these
circumstances.
Change-Id: I9a5e183bb3e4ab4c96c132d8cbe73ffa78715ef6
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