Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
Nebojsa Sabovic | c909da0 | 2010-05-07 16:15:13 -0700 | [diff] [blame] | 2 | |
mukesh agrawal | fe0e85b | 2011-08-09 14:24:15 -0700 | [diff] [blame] | 3 | # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 7 | """Connect to a WiFi service and report the amount of time it took |
Nebojsa Sabovic | c909da0 | 2010-05-07 16:15:13 -0700 | [diff] [blame] | 8 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 9 | This script initiates a connection to a WiFi service and reports |
| 10 | the time to major state changes (assoc, config). If the connection |
| 11 | fails within the desired time, it outputs the contents of the log |
| 12 | files during that intervening time. |
Paul Stewart | 6e6645d | 2010-09-27 09:58:00 -0700 | [diff] [blame] | 13 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 14 | """ |
| 15 | |
Gaurav Shah | bbb0b0b | 2011-10-25 17:58:18 -0700 | [diff] [blame] | 16 | import dbus |
| 17 | import gobject |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 18 | import logging |
| 19 | import optparse |
| 20 | import sys |
| 21 | import time |
| 22 | import traceback |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 23 | from site_wlan_wait_state import * |
| 24 | |
| 25 | FLIMFLAM_ERROR = FLIMFLAM + '.Error' |
| 26 | FLIMFLAM_ERROR_INPROGRESS = FLIMFLAM_ERROR + '.InProgress' |
| 27 | FLIMFLAM_ERROR_UNKNOWNMETHOD = FLIMFLAM_ERROR + '.UnknownMethod' |
| 28 | FLIMFLAM_ERROR_ALREADYCONNECTED = FLIMFLAM_ERROR + '.AlreadyConnected' |
Paul Stewart | 2b15b5e | 2010-06-11 11:53:19 -0700 | [diff] [blame] | 29 | connect_quirks = {} |
Nebojsa Sabovic | c909da0 | 2010-05-07 16:15:13 -0700 | [diff] [blame] | 30 | |
Sam Leffler | 45247a7 | 2011-04-13 10:43:55 -0700 | [diff] [blame] | 31 | def convert_dbus_value(value): |
| 32 | if value.__class__ == dbus.Byte: |
| 33 | return int(value) |
| 34 | elif value.__class__ == dbus.Boolean: |
| 35 | return bool(value) |
| 36 | else: |
| 37 | return value |
| 38 | |
| 39 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 40 | class ConnectStateHandler(StateHandler): |
| 41 | def __init__(self, dbus_bus, connection_settings, hidden, timeout, |
| 42 | start_time=None, debug=False, scan_retry=8): |
| 43 | self.connection_settings = connection_settings |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 44 | self.acquisition_time = None |
| 45 | self.authentication_time = None |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 46 | self.configuration_time = None |
Sam Leffler | 8ed0cb7 | 2011-02-23 15:58:28 -0800 | [diff] [blame] | 47 | self.frequency = 0 |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 48 | self.hidden = hidden |
Sam Leffler | a7394e2 | 2011-01-20 09:18:50 -0800 | [diff] [blame] | 49 | self.phymode = None |
| 50 | self.security = None |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 51 | self.service_handle = None |
| 52 | self.scan_timeout = None |
| 53 | self.scan_retry = scan_retry |
| 54 | StateHandler.__init__(self, dbus_bus, |
Paul Stewart | 6359c5e | 2012-01-31 16:05:40 -0800 | [diff] [blame] | 55 | [(connection_settings['SSID'], 'State', 'ready', |
| 56 | False, True)], |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 57 | timeout, None, timeout, debug) |
| 58 | if start_time: |
| 59 | self.run_start_time = start_time |
Paul Stewart | 5d1d162 | 2010-08-12 10:29:55 -0700 | [diff] [blame] | 60 | |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 61 | self.bus.add_signal_receiver(self.SupplicantChangeCallback, |
| 62 | signal_name='PropertiesChanged', |
| 63 | dbus_interface=SUPPLICANT+'.Interface') |
| 64 | |
Gaurav Shah | 6766d26 | 2011-11-01 19:21:45 -0700 | [diff] [blame] | 65 | |
| 66 | def _GetMatchedService(self, service_list): |
| 67 | """Get a service matching the connection setting from a list of services.""" |
| 68 | matched_service = None |
| 69 | for svc in service_list: |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 70 | props = svc.GetProperties() |
Paul Stewart | ba58af4 | 2011-05-02 16:24:08 -0700 | [diff] [blame] | 71 | set_props = {} |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 72 | for key, val in self.connection_settings.items(): |
Sam Leffler | 45247a7 | 2011-04-13 10:43:55 -0700 | [diff] [blame] | 73 | prop_val = convert_dbus_value(props.get(key)) |
| 74 | if key != 'SSID' and prop_val != val: |
| 75 | if key in ['Passphrase', 'SaveCredentials'] or key.startswith('EAP.'): |
Paul Stewart | ba58af4 | 2011-05-02 16:24:08 -0700 | [diff] [blame] | 76 | set_props[key] = val |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 77 | else: |
mukesh agrawal | fe0e85b | 2011-08-09 14:24:15 -0700 | [diff] [blame] | 78 | self.Debug( |
| 79 | 'Service key mismatch: %s (desired "%s" != available "%s")' % |
| 80 | (key, val, str(prop_val))) |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 81 | break |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 82 | else: |
Paul Stewart | ba58af4 | 2011-05-02 16:24:08 -0700 | [diff] [blame] | 83 | for key, val in set_props.iteritems(): |
| 84 | try: |
mukesh agrawal | fe0e85b | 2011-08-09 14:24:15 -0700 | [diff] [blame] | 85 | self.Debug('Setting property %s to %s' % (key, val)) |
Paul Stewart | ba58af4 | 2011-05-02 16:24:08 -0700 | [diff] [blame] | 86 | svc.SetProperty(key, val) |
| 87 | except dbus.exceptions.DBusException, e: |
| 88 | self.failure = ('SetProperty: DBus exception %s for set of %s' % |
| 89 | (e, key)) |
Gaurav Shah | 6766d26 | 2011-11-01 19:21:45 -0700 | [diff] [blame] | 90 | raise e |
| 91 | |
| 92 | matched_service = svc |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 93 | if self.scan_timeout is not None: |
| 94 | gobject.source_remove(self.scan_timeout) |
| 95 | self.scan_timeout = None |
Gaurav Shah | 6766d26 | 2011-11-01 19:21:45 -0700 | [diff] [blame] | 96 | return matched_service |
| 97 | |
| 98 | |
| 99 | def FindService(self, path_list=None): |
| 100 | service = None |
| 101 | try: |
| 102 | service = self._GetMatchedService( |
| 103 | FindObjects('Service', 'SSID', self.service_name, |
| 104 | path_list=path_list)) |
| 105 | except dbus.exceptions.DBusException, e: |
| 106 | # Failure reason must have been set by _GetMatchedService(). |
| 107 | return None |
| 108 | |
| 109 | if not service and self.hidden: |
| 110 | try: |
| 111 | path = manager.GetService( |
| 112 | dbus.Dictionary(self.connection_settings, signature='sv')) |
| 113 | service = dbus.Interface( |
| 114 | self.bus.get_object(FLIMFLAM, path), FLIMFLAM + '.Service') |
| 115 | except dbus.exceptions.DBusException, e: |
| 116 | self.failure = ('GetService: DBus exception %s for settings %s' % |
| 117 | (e, self.connection_settings)) |
| 118 | return None |
| 119 | elif not service: |
| 120 | if not self.scan_timeout: |
| 121 | self.DoScan() |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 122 | return None |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 123 | |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 124 | if not self.acquisition_time: |
| 125 | self.acquisition_time = time.time() |
| 126 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 127 | # If service isn't already connecting or connected, start now |
| 128 | if (service.GetProperties()['State'] not in ('association', 'configuration', |
| 129 | 'ready')): |
| 130 | try: |
| 131 | service.Connect() |
| 132 | except dbus.exceptions.DBusException, e: |
| 133 | if e.get_dbus_name() == FLIMFLAM_ERROR_INPROGRESS: |
| 134 | self.Debug('Service was already in progress (state=%s)' % |
| 135 | service.GetProperties().get('State')) |
| 136 | connect_quirks['in_progress'] = 1 |
Paul Stewart | 54c1371 | 2011-02-11 19:20:53 -0800 | [diff] [blame] | 137 | else: |
| 138 | print 'FAIL(acquire): DBus exception in Connect() %s' % e |
| 139 | ErrExit(2) |
mukesh agrawal | fe0e85b | 2011-08-09 14:24:15 -0700 | [diff] [blame] | 140 | else: |
| 141 | self.Debug("skipping Connect call, service is in %s state" % |
| 142 | service.GetProperties()['State']) |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 143 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 144 | self.service_handle = service |
| 145 | return service |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 146 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 147 | def DoScan(self): |
| 148 | self.scan_timeout = None |
| 149 | self.Debug('Service not found; requesting scan...') |
| 150 | try: |
| 151 | manager.RequestScan('wifi') |
| 152 | except dbus.exceptions.DBusException, e: |
| 153 | if e.get_dbus_name() != FLIMFLAM_ERROR_INPROGRESS: |
| 154 | raise |
| 155 | self.scan_timeout = gobject.timeout_add(int(self.scan_retry*1000), |
| 156 | self.DoScan) |
Paul Stewart | 6e6645d | 2010-09-27 09:58:00 -0700 | [diff] [blame] | 157 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 158 | def StateChanged(self): |
| 159 | # If we entered the "configuration" state, mark that down |
| 160 | if self.svc_state == 'configuration': |
| 161 | self.configuration_time = time.time() |
Sam Leffler | 8ed0cb7 | 2011-02-23 15:58:28 -0800 | [diff] [blame] | 162 | # NB: do this on all changes in case configuration is skipped |
| 163 | props = self.service_handle.GetProperties() |
| 164 | self.security = props.get('Security', None) |
| 165 | self.frequency = props.get('WiFi.Frequency', 0) |
| 166 | self.phymode = props.get('WiFi.PhyMode', None) |
Daniel Kurtz | c26804d | 2010-09-23 12:43:37 -0700 | [diff] [blame] | 167 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 168 | def Stage(self): |
| 169 | if not self.wait_path: |
| 170 | return 'acquire' |
| 171 | elif not self.configuration_time: |
| 172 | return 'assoc' |
| 173 | else: |
| 174 | return 'config' |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 175 | |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 176 | def SupplicantChangeCallback(self, args, **kwargs): |
| 177 | if 'State' in args: |
| 178 | state = args['State'] |
| 179 | self.Debug('Supplicant state is \'%s\'' % state) |
| 180 | if (not self.authentication_time and |
| 181 | (state == 'authenticating' or state == 'associating')): |
| 182 | self.authentication_time = time.time() |
| 183 | elif state == 'inactive' or state == 'disconnected': |
| 184 | self.authentication_time = None |
Paul Stewart | 6e6645d | 2010-09-27 09:58:00 -0700 | [diff] [blame] | 185 | |
Sam Leffler | 6621e95 | 2011-05-16 09:35:54 -0700 | [diff] [blame] | 186 | |
Paul Stewart | 499fd06 | 2010-08-27 11:32:32 -0700 | [diff] [blame] | 187 | def ErrExit(code): |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 188 | try: |
| 189 | handler.service_handle.Disconnect() |
| 190 | except: |
| 191 | pass |
| 192 | DumpLogs(logs) |
| 193 | sys.exit(code) |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 194 | |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 195 | |
Sam Leffler | 6621e95 | 2011-05-16 09:35:54 -0700 | [diff] [blame] | 196 | def split_psk(settings, psk): |
| 197 | cert_args = psk.split(':') |
| 198 | for i in xrange(0, len(cert_args), 2): |
| 199 | settings[cert_args[i]] = cert_args[i+1] |
| 200 | |
| 201 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 202 | def main(argv): |
| 203 | parser = optparse.OptionParser('Usage: %prog [options...] ' |
| 204 | 'ssid security psk assoc_timeout cfg_timeout') |
| 205 | parser.add_option('--hidden', dest='hidden', action='store_true', |
| 206 | help='This is a hidden network') |
| 207 | parser.add_option('--debug', dest='debug', action='store_true', |
| 208 | help='Report state changes and other debug info') |
Paul Stewart | c2b3de8 | 2011-03-03 14:45:31 -0800 | [diff] [blame] | 209 | parser.add_option('--mode', dest='mode', default='managed', |
Gaurav Shah | 6766d26 | 2011-11-01 19:21:45 -0700 | [diff] [blame] | 210 | help='AP mode') |
Sam Leffler | 45247a7 | 2011-04-13 10:43:55 -0700 | [diff] [blame] | 211 | parser.add_option('--nosave', dest='save_creds', action='store_false', |
| 212 | default=True, help='Do not save credentials') |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 213 | (options, args) = parser.parse_args(argv[1:]) |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 214 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 215 | if len(argv) <= 4: |
| 216 | parser.error('Required arguments: ssid security psk assoc_timeount ' |
| 217 | 'config_timeout') |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 218 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 219 | ssid = args[0] |
| 220 | security = args[1] |
| 221 | psk = args[2] |
| 222 | assoc_timeout = float(args[3]) |
| 223 | config_timeout = float(args[4]) |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 224 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 225 | connection_settings = { |
| 226 | 'Type': 'wifi', |
Paul Stewart | c2b3de8 | 2011-03-03 14:45:31 -0800 | [diff] [blame] | 227 | 'Mode': options.mode, |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 228 | 'SSID': ssid, |
Sam Leffler | 45247a7 | 2011-04-13 10:43:55 -0700 | [diff] [blame] | 229 | 'Security': security, |
| 230 | 'SaveCredentials' : options.save_creds |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 231 | } |
Paul Stewart | 2b15b5e | 2010-06-11 11:53:19 -0700 | [diff] [blame] | 232 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 233 | if security == '802_1x': |
Sam Leffler | 6621e95 | 2011-05-16 09:35:54 -0700 | [diff] [blame] | 234 | split_psk(connection_settings, psk) |
| 235 | elif security == '802_1x_wep': |
| 236 | split_psk(connection_settings, psk) |
| 237 | connection_settings['Security'] = 'wep' |
mukesh agrawal | 2b4d3e2 | 2011-11-18 23:05:18 +0000 | [diff] [blame] | 238 | elif security in ['wep', 'wpa', 'rsn', 'psk']: |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 239 | connection_settings['Passphrase'] = psk |
| 240 | |
| 241 | global logs |
| 242 | global handler |
| 243 | logs = OpenLogs('/var/log/messages') |
| 244 | |
| 245 | assoc_start = time.time() |
| 246 | handler = ConnectStateHandler(bus, connection_settings, options.hidden, |
| 247 | assoc_timeout, assoc_start, options.debug) |
| 248 | try: |
| 249 | if handler.NextState(): |
| 250 | handler.RunLoop() |
| 251 | except dbus.exceptions.DBusException, e: |
| 252 | if e.get_dbus_name() == FLIMFLAM_ERROR_INPROGRESS: |
| 253 | connect_quirks['in_progress'] = 1 |
| 254 | print>>sys.stderr, 'Previous connect is still in progress!' |
| 255 | if e.get_dbus_name() == FLIMFLAM_ERROR_UNKNOWNMETHOD: |
| 256 | connect_quirks['lost_dbus_connect'] = 1 |
| 257 | print>>sys.stderr, 'Lost the service handle during Connect()!' |
| 258 | if e.get_dbus_name() != FLIMFLAM_ERROR_ALREADYCONNECTED: |
| 259 | print 'FAIL(%s): ssid %s DBus exception %s' % (handler.Stage(), ssid, e) |
| 260 | ErrExit(2) |
| 261 | except Exception, e: |
| 262 | print 'FAIL(%s): ssid %s exception %s' % (handler.Stage(), ssid, e) |
| 263 | traceback.print_exc(file=sys.stderr) |
| 264 | ErrExit(2) |
| 265 | if handler.Failure(): |
| 266 | print 'FAIL(%s): ssid %s %s' % (handler.Stage(), ssid, handler.Failure()) |
| 267 | ErrExit(2) |
| 268 | |
| 269 | end = time.time() |
| 270 | config_start = handler.configuration_time |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 271 | acq_start = handler.acquisition_time |
| 272 | if acq_start: |
| 273 | acquire_time = acq_start - assoc_start |
| 274 | assoc_start = acq_start |
| 275 | else: |
| 276 | acquire_time = 0.0 |
| 277 | auth_start = handler.authentication_time |
| 278 | if auth_start: |
| 279 | wpa_select_time = auth_start - assoc_start |
| 280 | assoc_start = auth_start |
| 281 | else: |
| 282 | wpa_select_time = 0.0 |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 283 | if config_start: |
| 284 | config_time = end - config_start |
| 285 | assoc_time = config_start - assoc_start |
Paul Stewart | caaef36 | 2011-02-08 15:07:01 -0800 | [diff] [blame] | 286 | if assoc_time < 0.0: |
| 287 | assoc_time = 0.0 |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 288 | else: |
| 289 | config_time = 0.0 |
| 290 | assoc_time = end - assoc_start |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 291 | if not handler.Success(): |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 292 | print ('TIMEOUT(%s): ssid %s acquire %3.3f wpa_select %3.3f assoc %3.3f ' |
| 293 | 'config %3.3f secs state %s' % |
| 294 | (handler.Stage(), ssid, acquire_time, wpa_select_time, assoc_time, |
| 295 | config_time, |
| 296 | handler.svc_state)) |
Paul Stewart | 499fd06 | 2010-08-27 11:32:32 -0700 | [diff] [blame] | 297 | ErrExit(3) |
Nebojsa Sabovic | c909da0 | 2010-05-07 16:15:13 -0700 | [diff] [blame] | 298 | |
Sam Leffler | a7394e2 | 2011-01-20 09:18:50 -0800 | [diff] [blame] | 299 | print ('OK %3.3f %3.3f %3.3f %3.3f %d %s %s %s ' |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 300 | '(acquire wpa_select assoc and config times in sec, quirks)' % |
| 301 | (acquire_time, wpa_select_time, assoc_time, config_time, |
Sam Leffler | a7394e2 | 2011-01-20 09:18:50 -0800 | [diff] [blame] | 302 | handler.frequency, handler.phymode, handler.security, |
Paul Stewart | b88990e | 2011-01-19 11:06:27 -0800 | [diff] [blame] | 303 | str(connect_quirks.keys()))) |
Paul Stewart | 1ac1cea | 2010-06-10 15:35:05 -0700 | [diff] [blame] | 304 | |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 305 | if connect_quirks: |
Paul Stewart | 499fd06 | 2010-08-27 11:32:32 -0700 | [diff] [blame] | 306 | DumpLogs(logs) |
Paul Stewart | c805742 | 2010-12-14 16:03:48 -0800 | [diff] [blame] | 307 | sys.exit(0) |
| 308 | |
| 309 | if __name__ == '__main__': |
| 310 | main(sys.argv) |