blob: e5a95d7f72f96cc693ee64b3f033599dca30dd63 [file] [log] [blame]
Paul Stewartc8057422010-12-14 16:03:48 -08001#!/usr/bin/python
Nebojsa Sabovicc909da02010-05-07 16:15:13 -07002
mukesh agrawalfe0e85b2011-08-09 14:24:15 -07003# 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 Stewartc8057422010-12-14 16:03:48 -08007"""Connect to a WiFi service and report the amount of time it took
Nebojsa Sabovicc909da02010-05-07 16:15:13 -07008
Paul Stewartc8057422010-12-14 16:03:48 -08009This script initiates a connection to a WiFi service and reports
10the time to major state changes (assoc, config). If the connection
11fails within the desired time, it outputs the contents of the log
12files during that intervening time.
Paul Stewart6e6645d2010-09-27 09:58:00 -070013
Paul Stewartc8057422010-12-14 16:03:48 -080014"""
15
Gaurav Shahbbb0b0b2011-10-25 17:58:18 -070016import dbus
17import gobject
Paul Stewartc8057422010-12-14 16:03:48 -080018import logging
19import optparse
20import sys
21import time
22import traceback
Paul Stewartc8057422010-12-14 16:03:48 -080023from site_wlan_wait_state import *
24
25FLIMFLAM_ERROR = FLIMFLAM + '.Error'
26FLIMFLAM_ERROR_INPROGRESS = FLIMFLAM_ERROR + '.InProgress'
27FLIMFLAM_ERROR_UNKNOWNMETHOD = FLIMFLAM_ERROR + '.UnknownMethod'
28FLIMFLAM_ERROR_ALREADYCONNECTED = FLIMFLAM_ERROR + '.AlreadyConnected'
Paul Stewart2b15b5e2010-06-11 11:53:19 -070029connect_quirks = {}
Nebojsa Sabovicc909da02010-05-07 16:15:13 -070030
Sam Leffler45247a72011-04-13 10:43:55 -070031def 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 Stewartc8057422010-12-14 16:03:48 -080040class 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 Stewartb88990e2011-01-19 11:06:27 -080044 self.acquisition_time = None
45 self.authentication_time = None
Paul Stewartc8057422010-12-14 16:03:48 -080046 self.configuration_time = None
Sam Leffler8ed0cb72011-02-23 15:58:28 -080047 self.frequency = 0
Paul Stewartc8057422010-12-14 16:03:48 -080048 self.hidden = hidden
Sam Lefflera7394e22011-01-20 09:18:50 -080049 self.phymode = None
50 self.security = None
Paul Stewartc8057422010-12-14 16:03:48 -080051 self.service_handle = None
52 self.scan_timeout = None
53 self.scan_retry = scan_retry
54 StateHandler.__init__(self, dbus_bus,
Paul Stewart6359c5e2012-01-31 16:05:40 -080055 [(connection_settings['SSID'], 'State', 'ready',
56 False, True)],
Paul Stewartc8057422010-12-14 16:03:48 -080057 timeout, None, timeout, debug)
58 if start_time:
59 self.run_start_time = start_time
Paul Stewart5d1d1622010-08-12 10:29:55 -070060
Paul Stewartb88990e2011-01-19 11:06:27 -080061 self.bus.add_signal_receiver(self.SupplicantChangeCallback,
62 signal_name='PropertiesChanged',
63 dbus_interface=SUPPLICANT+'.Interface')
64
Gaurav Shah6766d262011-11-01 19:21:45 -070065
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 Stewartc8057422010-12-14 16:03:48 -080070 props = svc.GetProperties()
Paul Stewartba58af42011-05-02 16:24:08 -070071 set_props = {}
Paul Stewartc8057422010-12-14 16:03:48 -080072 for key, val in self.connection_settings.items():
Sam Leffler45247a72011-04-13 10:43:55 -070073 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 Stewartba58af42011-05-02 16:24:08 -070076 set_props[key] = val
Paul Stewartc8057422010-12-14 16:03:48 -080077 else:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070078 self.Debug(
79 'Service key mismatch: %s (desired "%s" != available "%s")' %
80 (key, val, str(prop_val)))
Paul Stewart1ac1cea2010-06-10 15:35:05 -070081 break
Paul Stewartc8057422010-12-14 16:03:48 -080082 else:
Paul Stewartba58af42011-05-02 16:24:08 -070083 for key, val in set_props.iteritems():
84 try:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070085 self.Debug('Setting property %s to %s' % (key, val))
Paul Stewartba58af42011-05-02 16:24:08 -070086 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 Shah6766d262011-11-01 19:21:45 -070090 raise e
91
92 matched_service = svc
Paul Stewartc8057422010-12-14 16:03:48 -080093 if self.scan_timeout is not None:
94 gobject.source_remove(self.scan_timeout)
95 self.scan_timeout = None
Gaurav Shah6766d262011-11-01 19:21:45 -070096 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 Stewartc8057422010-12-14 16:03:48 -0800122 return None
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700123
Paul Stewartb88990e2011-01-19 11:06:27 -0800124 if not self.acquisition_time:
125 self.acquisition_time = time.time()
126
Paul Stewartc8057422010-12-14 16:03:48 -0800127 # 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 Stewart54c13712011-02-11 19:20:53 -0800137 else:
138 print 'FAIL(acquire): DBus exception in Connect() %s' % e
139 ErrExit(2)
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700140 else:
141 self.Debug("skipping Connect call, service is in %s state" %
142 service.GetProperties()['State'])
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700143
Paul Stewartc8057422010-12-14 16:03:48 -0800144 self.service_handle = service
145 return service
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700146
Paul Stewartc8057422010-12-14 16:03:48 -0800147 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 Stewart6e6645d2010-09-27 09:58:00 -0700157
Paul Stewartc8057422010-12-14 16:03:48 -0800158 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 Leffler8ed0cb72011-02-23 15:58:28 -0800162 # 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 Kurtzc26804d2010-09-23 12:43:37 -0700167
Paul Stewartc8057422010-12-14 16:03:48 -0800168 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 Stewart1ac1cea2010-06-10 15:35:05 -0700175
Paul Stewartb88990e2011-01-19 11:06:27 -0800176 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 Stewart6e6645d2010-09-27 09:58:00 -0700185
Sam Leffler6621e952011-05-16 09:35:54 -0700186
Paul Stewart499fd062010-08-27 11:32:32 -0700187def ErrExit(code):
Paul Stewartc8057422010-12-14 16:03:48 -0800188 try:
189 handler.service_handle.Disconnect()
190 except:
191 pass
192 DumpLogs(logs)
193 sys.exit(code)
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700194
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700195
Sam Leffler6621e952011-05-16 09:35:54 -0700196def 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 Stewartc8057422010-12-14 16:03:48 -0800202def 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 Stewartc2b3de82011-03-03 14:45:31 -0800209 parser.add_option('--mode', dest='mode', default='managed',
Gaurav Shah6766d262011-11-01 19:21:45 -0700210 help='AP mode')
Sam Leffler45247a72011-04-13 10:43:55 -0700211 parser.add_option('--nosave', dest='save_creds', action='store_false',
212 default=True, help='Do not save credentials')
Paul Stewartc8057422010-12-14 16:03:48 -0800213 (options, args) = parser.parse_args(argv[1:])
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700214
Paul Stewartc8057422010-12-14 16:03:48 -0800215 if len(argv) <= 4:
216 parser.error('Required arguments: ssid security psk assoc_timeount '
217 'config_timeout')
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700218
Paul Stewartc8057422010-12-14 16:03:48 -0800219 ssid = args[0]
220 security = args[1]
221 psk = args[2]
222 assoc_timeout = float(args[3])
223 config_timeout = float(args[4])
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700224
Paul Stewartc8057422010-12-14 16:03:48 -0800225 connection_settings = {
226 'Type': 'wifi',
Paul Stewartc2b3de82011-03-03 14:45:31 -0800227 'Mode': options.mode,
Paul Stewartc8057422010-12-14 16:03:48 -0800228 'SSID': ssid,
Sam Leffler45247a72011-04-13 10:43:55 -0700229 'Security': security,
230 'SaveCredentials' : options.save_creds
Paul Stewartc8057422010-12-14 16:03:48 -0800231 }
Paul Stewart2b15b5e2010-06-11 11:53:19 -0700232
Paul Stewartc8057422010-12-14 16:03:48 -0800233 if security == '802_1x':
Sam Leffler6621e952011-05-16 09:35:54 -0700234 split_psk(connection_settings, psk)
235 elif security == '802_1x_wep':
236 split_psk(connection_settings, psk)
237 connection_settings['Security'] = 'wep'
mukesh agrawal2b4d3e22011-11-18 23:05:18 +0000238 elif security in ['wep', 'wpa', 'rsn', 'psk']:
Paul Stewartc8057422010-12-14 16:03:48 -0800239 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 Stewartb88990e2011-01-19 11:06:27 -0800271 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 Stewartc8057422010-12-14 16:03:48 -0800283 if config_start:
284 config_time = end - config_start
285 assoc_time = config_start - assoc_start
Paul Stewartcaaef362011-02-08 15:07:01 -0800286 if assoc_time < 0.0:
287 assoc_time = 0.0
Paul Stewartc8057422010-12-14 16:03:48 -0800288 else:
289 config_time = 0.0
290 assoc_time = end - assoc_start
Paul Stewartc8057422010-12-14 16:03:48 -0800291 if not handler.Success():
Paul Stewartb88990e2011-01-19 11:06:27 -0800292 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 Stewart499fd062010-08-27 11:32:32 -0700297 ErrExit(3)
Nebojsa Sabovicc909da02010-05-07 16:15:13 -0700298
Sam Lefflera7394e22011-01-20 09:18:50 -0800299 print ('OK %3.3f %3.3f %3.3f %3.3f %d %s %s %s '
Paul Stewartb88990e2011-01-19 11:06:27 -0800300 '(acquire wpa_select assoc and config times in sec, quirks)' %
301 (acquire_time, wpa_select_time, assoc_time, config_time,
Sam Lefflera7394e22011-01-20 09:18:50 -0800302 handler.frequency, handler.phymode, handler.security,
Paul Stewartb88990e2011-01-19 11:06:27 -0800303 str(connect_quirks.keys())))
Paul Stewart1ac1cea2010-06-10 15:35:05 -0700304
Paul Stewartc8057422010-12-14 16:03:48 -0800305 if connect_quirks:
Paul Stewart499fd062010-08-27 11:32:32 -0700306 DumpLogs(logs)
Paul Stewartc8057422010-12-14 16:03:48 -0800307 sys.exit(0)
308
309if __name__ == '__main__':
310 main(sys.argv)