Merge "conman: Also prioritize open APs by OUI and RSSI."
diff --git a/conman/connection_manager.py b/conman/connection_manager.py
index 7e2b24b..6ccdaa2 100755
--- a/conman/connection_manager.py
+++ b/conman/connection_manager.py
@@ -23,9 +23,6 @@
import iw
import status
-GFIBER_OUIS = ['f4:f5:e8']
-VENDOR_IE_FEATURE_ID_AUTOPROVISIONING = '01'
-
class FileChangeHandler(pyinotify.ProcessEvent):
"""Connects pyinotify events to ConnectionManager."""
@@ -657,10 +654,8 @@
subprocess.call(self.IFUP + [wifi.name])
# /bin/wifi takes a --band option but then finds the right interface for it,
# so it's okay to just pick the first band here.
- with_ie, without_ie = self._find_bssids(wifi.bands[0])
+ items = self._find_bssids(wifi.bands[0])
logging.info('Done scanning on %s', wifi.name)
- items = [(bss_info, 3) for bss_info in with_ie]
- items += [(bss_info, 1) for bss_info in without_ie]
if not hasattr(wifi, 'cycler'):
wifi.cycler = cycler.AgingPriorityCycler(
cycle_length_s=self._bssid_cycle_length_s)
@@ -670,13 +665,8 @@
wifi.cycler.update(items)
def _find_bssids(self, band):
- def supports_autoprovisioning(oui, vendor_ie):
- if oui not in GFIBER_OUIS:
- return False
-
- return vendor_ie.startswith(VENDOR_IE_FEATURE_ID_AUTOPROVISIONING)
-
- return iw.find_bssids(band, supports_autoprovisioning, False)
+ """Wrapper used as a unit testing seam."""
+ return iw.find_bssids(band, False)
def _try_next_bssid(self, wifi):
"""Attempt to connect to the next BSSID in wifi's BSSID cycler.
diff --git a/conman/iw.py b/conman/iw.py
index 300c3e2..fd56e32 100755
--- a/conman/iw.py
+++ b/conman/iw.py
@@ -17,8 +17,13 @@
return ''
+GFIBER_OUIS = ['f4:f5:e8']
+VENDOR_IE_FEATURE_ID_AUTOPROVISIONING = '01'
+
+
_BSSID_RE = r'BSS (?P<BSSID>([0-9a-f]{2}:?){6})\(on .*\)'
_SSID_RE = r'SSID: (?P<SSID>.*)'
+_RSSI_RE = r'signal: (?P<RSSI>.*) dBm'
_VENDOR_IE_RE = (r'Vendor specific: OUI (?P<OUI>([0-9a-f]{2}:?){3}), '
'data:(?P<data>( [0-9a-f]{2})+)')
@@ -26,15 +31,17 @@
class BssInfo(object):
"""Contains info about a BSS, parsed from 'iw scan'."""
- def __init__(self, bssid='', ssid='', security=None, vendor_ies=None):
+ def __init__(self, bssid='', ssid='', rssi=-100, security=None,
+ vendor_ies=None):
self.bssid = bssid
self.ssid = ssid
+ self.rssi = rssi
self.vendor_ies = vendor_ies or []
self.security = security or []
def __attrs(self):
return (self.bssid, self.ssid, tuple(sorted(self.vendor_ies)),
- tuple(sorted(self.security)))
+ tuple(sorted(self.security)), self.rssi)
def __eq__(self, other):
# pylint: disable=protected-access
@@ -70,6 +77,10 @@
if match:
bss_info.ssid = match.group('SSID')
continue
+ match = re.match(_RSSI_RE, line)
+ if match:
+ bss_info.rssi = float(match.group('RSSI'))
+ continue
match = re.match(_VENDOR_IE_RE, line)
if match:
bss_info.vendor_ies.append((match.group('OUI'),
@@ -88,22 +99,20 @@
return result
-def find_bssids(band, vendor_ie_function, include_secure):
+def find_bssids(band, include_secure):
"""Return information about interesting access points.
Args:
band: The band on which to scan.
- vendor_ie_function: A function that takes a vendor IE and returns a bool.
include_secure: Whether to exclude secure networks.
Returns:
- Two lists of tuples of the form (SSID, BSSID info dict). The first list has
- BSSIDs which have a vendor IE accepted by vendor_ie_function, and the second
- list has those which don't.
+ A list of (BSSID, priority) tuples, prioritizing BSSIDs with the GFiber
+ provisioning vendor IE > GFiber APs > other APs, and by RSSI within each
+ group.
"""
parsed = scan_parsed(band)
- result_with_ie = set()
- result_without_ie = set()
+ bssids = set()
for bss_info in parsed:
if bss_info.security and not include_secure:
@@ -121,11 +130,16 @@
if not bss_info.ssid and not bss_info.vendor_ies:
bss_info.ssid = DEFAULT_GFIBERSETUP_SSID
- for oui, data in bss_info.vendor_ies:
- if vendor_ie_function(oui, data):
- result_with_ie.add(bss_info)
- break
- else:
- result_without_ie.add(bss_info)
+ bssids.add(bss_info)
- return result_with_ie, result_without_ie
+ return [(bss_info, _bssid_priority(bss_info)) for bss_info in bssids]
+
+
+def _bssid_priority(bss_info):
+ result = 4 if bss_info.bssid[:8] in GFIBER_OUIS else 2
+ for oui, data in bss_info.vendor_ies:
+ if (oui in GFIBER_OUIS and
+ data.startswith(VENDOR_IE_FEATURE_ID_AUTOPROVISIONING)):
+ result = 5
+
+ return result + (100 + (max(bss_info.rssi, -100))) / 100.0
diff --git a/conman/iw_test.py b/conman/iw_test.py
index 3f80d6c..3bb3cf7 100755
--- a/conman/iw_test.py
+++ b/conman/iw_test.py
@@ -551,6 +551,7 @@
* VI: CW 7-15, AIFSN 2, TXOP 3008 usec
* VO: CW 3-7, AIFSN 2, TXOP 1504 usec
Vendor specific: OUI 00:11:22, data: 01 23 45 67
+ Vendor specific: OUI f4:f5:e8, data: 01
Vendor specific: OUI f4:f5:e8, data: 03 47 46 69 62 65 72 53 65 74 75 70 41 75 74 6f 6d 61 74 69 6f 6e
BSS f4:f5:e8:f1:36:43(on wcli0)
TSF: 12499150000 usec (0d, 03:28:19)
@@ -629,49 +630,55 @@
def find_bssids_test():
"""Test iw.find_bssids."""
test_ie = ('00:11:22', '01 23 45 67')
+ provisioning_ie = ('f4:f5:e8', '01')
ssid_ie = (
'f4:f5:e8',
'03 47 46 69 62 65 72 53 65 74 75 70 41 75 74 6f 6d 61 74 69 6f 6e',
)
short_scan_result = iw.BssInfo(ssid='short scan result',
bssid='00:23:97:57:f4:d8',
+ rssi=-60,
security=['WEP'],
vendor_ies=[test_ie])
provisioning_bss_info = iw.BssInfo(ssid=iw.DEFAULT_GFIBERSETUP_SSID,
bssid='94:b4:0f:f1:36:42',
- vendor_ies=[test_ie, ssid_ie])
+ rssi=-66,
+ vendor_ies=[test_ie, provisioning_ie,
+ ssid_ie])
provisioning_bss_info_frenzy = iw.BssInfo(ssid=iw.DEFAULT_GFIBERSETUP_SSID,
- bssid='f4:f5:e8:f1:36:43')
-
- with_ie, without_ie = iw.find_bssids('wcli0', lambda o, d: o == '00:11:22',
- True)
-
- wvtest.WVPASSEQ(with_ie, set([short_scan_result, provisioning_bss_info]))
+ bssid='f4:f5:e8:f1:36:43',
+ rssi=-66)
wvtest.WVPASSEQ(
- without_ie,
- set([provisioning_bss_info_frenzy,
- iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:36:41'),
- iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:3a:e1'),
- iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:35:61'),
- iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:36:40',
- security=['WPA2']),
- iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:3a:e0',
- security=['WPA2']),
- iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:35:60',
- security=['WPA2']),
- iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:02:a0',
- security=['WPA2'])]))
+ set(iw.find_bssids('wcli0', True)),
+ set([(short_scan_result, 2.4),
+ (provisioning_bss_info, 5.34),
+ (provisioning_bss_info_frenzy, 4.34),
+ (iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:36:41', rssi=-67),
+ 2.33),
+ (iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:3a:e1', rssi=-65),
+ 2.35),
+ (iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:35:61', rssi=-38),
+ 2.62),
+ (iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:36:40', rssi=-66,
+ security=['WPA2']), 2.34),
+ (iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:3a:e0', rssi=-55,
+ security=['WPA2']), 2.45),
+ (iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:35:60', rssi=-39,
+ security=['WPA2']), 2.61),
+ (iw.BssInfo(ssid='Google', bssid='94:b4:0f:f1:02:a0', rssi=-54,
+ security=['WPA2']), 2.46)]))
- with_ie, without_ie = iw.find_bssids('wcli0', lambda o, d: o == '00:11:22',
- False)
- wvtest.WVPASSEQ(with_ie, set([provisioning_bss_info]))
wvtest.WVPASSEQ(
- without_ie,
- set([provisioning_bss_info_frenzy,
- iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:36:41'),
- iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:3a:e1'),
- iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:35:61')]))
+ set(iw.find_bssids('wcli0', False)),
+ set([(provisioning_bss_info, 5.34),
+ (provisioning_bss_info_frenzy, 4.34),
+ (iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:36:41', rssi=-67),
+ 2.33),
+ (iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:3a:e1', rssi=-65),
+ 2.35),
+ (iw.BssInfo(ssid='GoogleGuest', bssid='94:b4:0f:f1:35:61', rssi=-38),
+ 2.62)]))
if __name__ == '__main__':
wvtest.wvtest_main()