blob: abbfb3d56c02cbbb4772fcfd50c462a862c38e88 [file] [log] [blame]
Sam Leffler6969d1d2010-03-15 16:07:11 -07001# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Christopher Wiley14796b32013-04-03 14:53:33 -07005import logging
Christopher Wiley3166e432013-08-06 09:53:12 -07006import random
Christopher Wiley14796b32013-04-03 14:53:33 -07007import re
Christopher Wiley3166e432013-08-06 09:53:12 -07008import string
Christopher Wiley1defc242013-09-18 10:28:37 -07009import time
Christopher Wiley14796b32013-04-03 14:53:33 -070010
Paul Stewartc9628b32010-08-11 13:03:51 -070011from autotest_lib.client.common_lib import error
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070012from autotest_lib.server import site_linux_system
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070013from autotest_lib.server.cros import wifi_test_utils
Christopher Wiley99d42c92013-07-09 16:40:16 -070014from autotest_lib.server.cros.network import hostap_config
Sam Leffler19bb0a72010-04-12 08:51:08 -070015
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070016def isLinuxRouter(host):
17 """Check if host is a linux router.
18
19 @param host Host object representing the remote machine.
20 @return True iff remote system is a Linux system.
21
22 """
23 router_uname = host.run('uname').stdout
Sam Leffler19bb0a72010-04-12 08:51:08 -070024 return re.search('Linux', router_uname)
25
Christopher Wiley1febd6a2013-06-03 13:59:48 -070026
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070027class LinuxRouter(site_linux_system.LinuxSystem):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070028 """Linux/mac80211-style WiFi Router support for WiFiTest class.
Sam Leffler6969d1d2010-03-15 16:07:11 -070029
30 This class implements test methods/steps that communicate with a
31 router implemented with Linux/mac80211. The router must
32 be pre-configured to enable ssh access and have a mac80211-based
33 wireless device. We also assume hostapd 0.7.x and iw are present
34 and any necessary modules are pre-loaded.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070035
Sam Leffler6969d1d2010-03-15 16:07:11 -070036 """
37
Christopher Wiley3166e432013-08-06 09:53:12 -070038 KNOWN_TEST_PREFIX = 'network_WiFi'
Christopher Wiley1defc242013-09-18 10:28:37 -070039 STARTUP_POLLING_INTERVAL_SECONDS = 0.5
40 STARTUP_TIMEOUT_SECONDS = 10
Christopher Wiley3166e432013-08-06 09:53:12 -070041 SUFFIX_LETTERS = string.ascii_lowercase + string.digits
Sam Leffler6969d1d2010-03-15 16:07:11 -070042
Paul Stewart51b0f382013-06-12 09:03:02 -070043 def get_capabilities(self):
44 """@return iterable object of AP capabilities for this system."""
45 caps = set()
46 try:
47 self.cmd_send_management_frame = wifi_test_utils.must_be_installed(
48 self.router, '/usr/bin/send_management_frame')
49 caps.add(self.CAPABILITY_SEND_MANAGEMENT_FRAME)
50 except error.TestFail:
51 pass
52 return super(LinuxRouter, self).get_capabilities().union(caps)
53
54
Christopher Wiley3166e432013-08-06 09:53:12 -070055 def __init__(self, host, params, test_name):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070056 """Build a LinuxRouter.
57
58 @param host Host object representing the remote machine.
59 @param params dict of settings from site_wifitest based tests.
Christopher Wiley3166e432013-08-06 09:53:12 -070060 @param test_name string name of this test. Used in SSID creation.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070061
62 """
63 site_linux_system.LinuxSystem.__init__(self, host, params, 'router')
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070064 self._remove_interfaces()
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070065
Wade Guthrie24d1e312012-04-24 16:53:40 -070066 # Router host.
67 self.router = host
68
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070069 self.cmd_hostapd = wifi_test_utils.must_be_installed(
70 host, params.get('cmd_hostapd', '/usr/sbin/hostapd'))
71 self.cmd_hostapd_cli = params.get('cmd_hostapd_cli',
72 '/usr/sbin/hostapd_cli')
73 self.dhcpd_conf = '/tmp/dhcpd.%s.conf'
74 self.dhcpd_leases = '/tmp/dhcpd.leases'
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070075
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070076 # hostapd configuration persists throughout the test, subsequent
77 # 'config' commands only modify it.
Christopher Wiley3166e432013-08-06 09:53:12 -070078 self.ssid_prefix = test_name
79 if self.ssid_prefix.startswith(self.KNOWN_TEST_PREFIX):
80 # Many of our tests start with an uninteresting prefix.
81 # Remove it so we can have more unique bytes.
82 self.ssid_prefix = self.ssid_prefix[len(self.KNOWN_TEST_PREFIX):]
83 self.ssid_prefix = self.ssid_prefix.lstrip('_')
84 self.ssid_prefix += '_'
85
Paul Stewartd5aafa92013-03-24 19:06:14 -070086 self.default_config = {
Paul Stewartd5aafa92013-03-24 19:06:14 -070087 'hw_mode': 'g',
88 'ctrl_interface': '/tmp/hostapd-test.control',
89 'logger_syslog': '-1',
90 'logger_syslog_level': '0'
91 }
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070092 self.hostapd = {
93 'configured': False,
Paul Stewart326badb2012-12-18 14:18:54 -080094 'config_file': "/tmp/hostapd-test-%s.conf",
95 'log_file': "/tmp/hostapd-test-%s.log",
Christopher Wiley1defc242013-09-18 10:28:37 -070096 'pid_file': "/tmp/hostapd-test-%s.pid",
Paul Stewartf854d2e2011-05-04 13:19:18 -070097 'log_count': 0,
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070098 'driver': "nl80211",
Paul Stewartd5aafa92013-03-24 19:06:14 -070099 'conf': self.default_config.copy()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700100 }
Paul Stewartc2b3de82011-03-03 14:45:31 -0800101 self.station = {
102 'configured': False,
Christopher Wiley3166e432013-08-06 09:53:12 -0700103 'conf': {},
Paul Stewartc2b3de82011-03-03 14:45:31 -0800104 }
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700105 self.local_servers = []
Paul Stewart548cf452012-11-27 17:46:23 -0800106 self.hostapd_instances = []
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700107 self.force_local_server = "force_local_server" in params
108 self.dhcp_low = 1
109 self.dhcp_high = 128
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700110
Paul Stewart548cf452012-11-27 17:46:23 -0800111 # Kill hostapd and dhcp server if already running.
Thieu Le7b23a542012-01-27 15:54:48 -0800112 self.kill_hostapd()
Paul Stewart548cf452012-11-27 17:46:23 -0800113 self.stop_dhcp_servers()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700114
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -0700115 # Place us in the US by default
116 self.router.run("%s reg set US" % self.cmd_iw)
Sam Leffler6969d1d2010-03-15 16:07:11 -0700117
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700118
Christopher Wileyf4bc88b2013-08-29 16:45:15 -0700119 def close(self):
120 """Close global resources held by this system."""
121 self.destroy()
122 super(LinuxRouter, self).close()
123
124
Sam Leffler6969d1d2010-03-15 16:07:11 -0700125 def create(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700126 """Create a wifi device of the specified type.
Christopher Wiley14796b32013-04-03 14:53:33 -0700127
128 @param params dict containing the device type under key 'type'.
129
130 """
131 self.create_wifi_device(params['type'])
132
133
134 def create_wifi_device(self, device_type='hostap'):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700135 """Create a wifi device of the specified type.
Christopher Wiley14796b32013-04-03 14:53:33 -0700136
137 Defaults to creating a hostap managed device.
138
139 @param device_type string device type.
140
141 """
Sam Leffler6969d1d2010-03-15 16:07:11 -0700142 #
143 # AP mode is handled entirely by hostapd so we only
144 # have to setup others (mapping the bsd type to what
145 # iw wants)
146 #
147 # map from bsd types to iw types
Christopher Wiley14796b32013-04-03 14:53:33 -0700148 self.apmode = device_type in ('ap', 'hostap')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800149 if not self.apmode:
Christopher Wiley14796b32013-04-03 14:53:33 -0700150 self.station['type'] = device_type
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700151 self.phytype = {
Christopher Wiley14796b32013-04-03 14:53:33 -0700152 'sta' : 'managed',
153 'monitor' : 'monitor',
154 'adhoc' : 'adhoc',
155 'ibss' : 'ibss',
156 'ap' : 'managed', # NB: handled by hostapd
157 'hostap' : 'managed', # NB: handled by hostapd
158 'mesh' : 'mesh',
159 'wds' : 'wds',
160 }[device_type]
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700161
Sam Leffler6969d1d2010-03-15 16:07:11 -0700162
Christopher Wileyd89b5282013-04-10 15:21:26 -0700163 def destroy(self, params={}):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700164 """Destroy a previously created device.
165
166 @param params dict of site_wifitest parameters.
167
168 """
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700169 self.deconfig(params)
Paul Stewartd5aafa92013-03-24 19:06:14 -0700170 self.hostapd['conf'] = self.default_config.copy()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700171
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700172
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700173 def has_local_server(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700174 """@return True iff this router has local servers configured."""
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700175 return bool(self.local_servers)
Sam Leffler6969d1d2010-03-15 16:07:11 -0700176
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700177
Paul Stewart9e3ff0b2011-08-17 20:35:19 -0700178 def cleanup(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700179 """Clean up any resources in use.
180
181 @param params dict of site_wifitest parameters.
182
183 """
Paul Stewart9e3ff0b2011-08-17 20:35:19 -0700184 # For linux, this is a no-op
185 pass
186
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700187
Paul Stewart548cf452012-11-27 17:46:23 -0800188 def start_hostapd(self, conf, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700189 """Start a hostapd instance described by conf.
190
191 @param conf dict of hostapd configuration parameters.
192 @param params dict of site_wifitest parameters.
193
194 """
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700195 logging.info('Starting hostapd with parameters: %r', conf)
Paul Stewart548cf452012-11-27 17:46:23 -0800196 # Figure out the correct interface.
Paul Stewart326badb2012-12-18 14:18:54 -0800197 interface = self._get_wlanif(self.hostapd['frequency'],
198 self.phytype,
199 mode=conf.get('hw_mode', 'b'))
200
201 conf_file = self.hostapd['config_file'] % interface
202 log_file = self.hostapd['log_file'] % interface
Christopher Wiley1defc242013-09-18 10:28:37 -0700203 pid_file = self.hostapd['pid_file'] % interface
Paul Stewart326badb2012-12-18 14:18:54 -0800204 conf['interface'] = interface
Paul Stewart548cf452012-11-27 17:46:23 -0800205
206 # Generate hostapd.conf.
207 self._pre_config_hook(conf)
208 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
209 (conf_file, '\n'.join(
210 "%s=%s" % kv for kv in conf.iteritems())))
211
212 # Run hostapd.
213 logging.info("Starting hostapd...")
Christopher Wiley1defc242013-09-18 10:28:37 -0700214 self.router.run('rm %s' % log_file, ignore_status=True)
215 self.router.run('rm %s' % pid_file, ignore_status=True)
Paul Stewart548cf452012-11-27 17:46:23 -0800216 self._pre_start_hook(params)
Christopher Wiley1defc242013-09-18 10:28:37 -0700217 self.router.run("%s -dd -B -t -f %s -P %s %s" %
218 (self.cmd_hostapd, log_file, pid_file, conf_file))
219 pid = int(self.router.run('cat %s' % pid_file).stdout)
220
221 # Wait for confirmation that the router came up.
222 logging.info('Waiting for hostapd to startup.')
223 start_time = time.time()
224 while time.time() - start_time < self.STARTUP_TIMEOUT_SECONDS:
225 success = self.router.run(
226 'grep "Completing interface initialization" %s' % log_file,
227 ignore_status=True).exit_status == 0
228 if success:
229 break
230
231 # A common failure is to request an invalid router configuration.
232 # Detect this and exit early if we see it.
233 bad_config = self.router.run(
234 'grep "Interface initialization failed" %s' % log_file,
235 ignore_status=True).exit_status == 0
236 if bad_config:
237 raise error.TestFail('hostapd failed to initialize AP '
238 'interface.')
239
240 early_exit = self.router.run('kill -0 %d' % pid,
241 ignore_status=True).exit_status
242 if early_exit:
243 raise error.TestFail('hostapd process terminated.')
244
245 time.sleep(self.STARTUP_POLLING_INTERVAL_SECONDS)
246 else:
247 raise error.TestFail('Timed out while waiting for hostapd '
248 'to start.')
Paul Stewart548cf452012-11-27 17:46:23 -0800249
250 self.hostapd_instances.append({
251 'conf_file': conf_file,
252 'log_file': log_file,
Christopher Wiley1defc242013-09-18 10:28:37 -0700253 'interface': interface,
254 'pid_file': pid_file
Paul Stewart548cf452012-11-27 17:46:23 -0800255 })
256
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700257
Paul Stewart326badb2012-12-18 14:18:54 -0800258 def _kill_process_instance(self, process, instance=None, wait=0):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700259 """Kill a process on the router.
260
Paul Stewart326badb2012-12-18 14:18:54 -0800261 Kills program named |process|, optionally only a specific
262 |instance|. If |wait| is specified, we makes sure |process| exits
263 before returning.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700264
265 @param process string name of process to kill.
266 @param instance string instance of process to kill.
267 @param wait int timeout in seconds to wait for.
268
Thieu Le7b23a542012-01-27 15:54:48 -0800269 """
Paul Stewart21737812012-12-06 11:03:32 -0800270 if instance:
Paul Stewart326badb2012-12-18 14:18:54 -0800271 search_arg = '-f "%s.*%s"' % (process, instance)
Paul Stewart21737812012-12-06 11:03:32 -0800272 else:
Paul Stewart326badb2012-12-18 14:18:54 -0800273 search_arg = process
Paul Stewart21737812012-12-06 11:03:32 -0800274
Paul Stewart326badb2012-12-18 14:18:54 -0800275 cmd = "pkill %s >/dev/null 2>&1" % search_arg
276
277 if wait:
278 cmd += (" && while pgrep %s &> /dev/null; do sleep 1; done" %
279 search_arg)
280 self.router.run(cmd, timeout=wait, ignore_status=True)
281 else:
282 self.router.run(cmd, ignore_status=True)
283
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700284
Paul Stewart326badb2012-12-18 14:18:54 -0800285 def kill_hostapd_instance(self, instance):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700286 """Kills a hostapd instance.
287
288 @param instance string instance to kill.
289
290 """
Paul Stewart326badb2012-12-18 14:18:54 -0800291 self._kill_process_instance('hostapd', instance, 30)
Thieu Le7b23a542012-01-27 15:54:48 -0800292
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700293
Paul Stewart21737812012-12-06 11:03:32 -0800294 def kill_hostapd(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700295 """Kill all hostapd instances."""
Paul Stewart21737812012-12-06 11:03:32 -0800296 self.kill_hostapd_instance(None)
297
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700298
299 def __get_default_hostap_config(self):
300 """@return dict of default options for hostapd."""
301 conf = self.hostapd['conf']
302 # default RTS and frag threshold to ``off''
303 conf['rts_threshold'] = '2347'
304 conf['fragm_threshold'] = '2346'
305 conf['driver'] = self.hostapd['driver']
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700306 conf['ssid'] = self._build_ssid('')
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700307 return conf
308
309
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700310 def _build_ssid(self, suffix):
Christopher Wiley3166e432013-08-06 09:53:12 -0700311 unique_salt = ''.join([random.choice(self.SUFFIX_LETTERS)
312 for x in range(5)])
313 return (self.ssid_prefix + unique_salt + suffix)[-32:]
314
315
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700316 def hostap_configure(self, configuration, multi_interface=None):
317 """Build up a hostapd configuration file and start hostapd.
318
319 Also setup a local server if this router supports them.
320
321 @param configuration HosetapConfig object.
322 @param multi_interface bool True iff multiple interfaces allowed.
323
324 """
325 if multi_interface is None and (self.hostapd['configured'] or
326 self.station['configured']):
327 self.deconfig()
328 # Start with the default hostapd config parameters.
329 conf = self.__get_default_hostap_config()
Christopher Wiley3166e432013-08-06 09:53:12 -0700330 conf['ssid'] = (configuration.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700331 self._build_ssid(configuration.ssid_suffix))
Christopher Wiley9b406202013-05-06 14:07:49 -0700332 if configuration.bssid:
333 conf['bssid'] = configuration.bssid
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700334 conf['channel'] = configuration.channel
335 self.hostapd['frequency'] = configuration.frequency
336 conf['hw_mode'] = configuration.hw_mode
337 if configuration.hide_ssid:
338 conf['ignore_broadcast_ssid'] = 1
339 if configuration.is_11n:
340 conf['ieee80211n'] = 1
341 conf['ht_capab'] = ''.join(configuration.n_capabilities)
342 if configuration.wmm_enabled:
343 conf['wmm_enabled'] = 1
344 if configuration.require_ht:
345 conf['require_ht'] = 1
Christopher Wiley9fa7c632013-05-01 11:58:06 -0700346 if configuration.beacon_interval:
347 conf['beacon_int'] = configuration.beacon_interval
Christopher Wileya51258e2013-05-03 13:05:06 -0700348 if configuration.dtim_period:
349 conf['dtim_period'] = configuration.dtim_period
Christopher Wileye1235b62013-05-03 15:09:34 -0700350 if configuration.frag_threshold:
351 conf['fragm_threshold'] = configuration.frag_threshold
Christopher Wileyebdc27d2013-06-28 14:35:41 -0700352 if configuration.pmf_support:
353 conf['ieee80211w'] = configuration.pmf_support
Paul Stewart4ae471e2013-09-04 15:42:35 -0700354 if configuration.obss_interval:
355 conf['obss_interval'] = configuration.obss_interval
Christopher Wileyb8921c72013-06-13 09:51:47 -0700356 conf.update(configuration.get_security_hostapd_conf())
Christopher Wileya89706d2013-06-12 13:20:58 -0700357
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700358 self.start_hostapd(conf, {})
359 # Configure transmit power
360 tx_power_params = {'interface': conf['interface']}
361 # TODO(wiley) support for setting transmit power
362 self.set_txpower(tx_power_params)
363 if self.force_local_server:
364 self.start_local_server(conf['interface'])
365 self._post_start_hook({})
366 logging.info('AP configured.')
367 self.hostapd['configured'] = True
368
369
Paul Stewartc2b3de82011-03-03 14:45:31 -0800370 def hostap_config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700371 """Configure the AP per test requirements.
Sam Leffler6969d1d2010-03-15 16:07:11 -0700372
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700373 @param params dict of site_wifitest parameters.
374
375 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700376 # keep parameter modifications local-only
377 orig_params = params
378 params = params.copy()
379
Paul Stewart45338d22010-10-21 10:57:02 -0700380 multi_interface = 'multi_interface' in params
381 if multi_interface:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700382 # remove non-hostapd config item from params
Paul Stewart45338d22010-10-21 10:57:02 -0700383 params.pop('multi_interface')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800384 elif self.hostapd['configured'] or self.station['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700385 self.deconfig()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700386
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700387 local_server = params.pop('local_server', False)
388
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700389 conf = self.__get_default_hostap_config()
Paul Stewartc2b3de82011-03-03 14:45:31 -0800390 tx_power_params = {}
391 htcaps = set()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700392
Paul Stewartc2b3de82011-03-03 14:45:31 -0800393 for k, v in params.iteritems():
394 if k == 'ssid':
395 conf['ssid'] = v
396 elif k == 'ssid_suffix':
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700397 conf['ssid'] = self._build_ssid(v)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800398 elif k == 'channel':
399 freq = int(v)
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700400 self.hostapd['frequency'] = freq
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700401
Paul Stewartc2b3de82011-03-03 14:45:31 -0800402 # 2.4GHz
403 if freq <= 2484:
404 # Make sure hw_mode is set
405 if conf.get('hw_mode') == 'a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700406 conf['hw_mode'] = 'g'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800407
408 # Freq = 5 * chan + 2407, except channel 14
409 if freq == 2484:
410 conf['channel'] = 14
411 else:
412 conf['channel'] = (freq - 2407) / 5
413 # 5GHz
Sam Leffler6969d1d2010-03-15 16:07:11 -0700414 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800415 # Make sure hw_mode is set
416 conf['hw_mode'] = 'a'
417 # Freq = 5 * chan + 4000
418 if freq < 5000:
419 conf['channel'] = (freq - 4000) / 5
420 # Freq = 5 * chan + 5000
421 else:
422 conf['channel'] = (freq - 5000) / 5
Sam Leffler6969d1d2010-03-15 16:07:11 -0700423
Paul Stewartc2b3de82011-03-03 14:45:31 -0800424 elif k == 'country':
425 conf['country_code'] = v
426 elif k == 'dotd':
427 conf['ieee80211d'] = 1
428 elif k == '-dotd':
429 conf['ieee80211d'] = 0
430 elif k == 'mode':
431 if v == '11a':
432 conf['hw_mode'] = 'a'
433 elif v == '11g':
434 conf['hw_mode'] = 'g'
435 elif v == '11b':
436 conf['hw_mode'] = 'b'
437 elif v == '11n':
438 conf['ieee80211n'] = 1
439 elif k == 'bintval':
440 conf['beacon_int'] = v
441 elif k == 'dtimperiod':
442 conf['dtim_period'] = v
443 elif k == 'rtsthreshold':
444 conf['rts_threshold'] = v
445 elif k == 'fragthreshold':
446 conf['fragm_threshold'] = v
447 elif k == 'shortpreamble':
448 conf['preamble'] = 1
449 elif k == 'authmode':
450 if v == "open":
451 conf['auth_algs'] = 1
452 elif v == "shared":
453 conf['auth_algs'] = 2
454 elif k == 'hidessid':
455 conf['ignore_broadcast_ssid'] = 1
456 elif k == 'wme':
457 conf['wmm_enabled'] = 1
458 elif k == '-wme':
459 conf['wmm_enabled'] = 0
460 elif k == 'deftxkey':
461 conf['wep_default_key'] = v
462 elif k == 'ht20':
463 htcaps.add('') # NB: ensure 802.11n setup below
464 conf['wmm_enabled'] = 1
465 elif k == 'ht40':
466 htcaps.add('[HT40-]')
467 htcaps.add('[HT40+]')
468 conf['wmm_enabled'] = 1
Paul Stewartc1df8d62011-04-07 14:28:15 -0700469 elif k in ('ht40+', 'ht40-'):
470 htcaps.add('[%s]' % k.upper())
471 conf['wmm_enabled'] = 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800472 elif k == 'shortgi':
473 htcaps.add('[SHORT-GI-20]')
474 htcaps.add('[SHORT-GI-40]')
475 elif k == 'pureg':
476 pass # TODO(sleffler) need hostapd support
477 elif k == 'puren':
478 pass # TODO(sleffler) need hostapd support
479 elif k == 'protmode':
480 pass # TODO(sleffler) need hostapd support
481 elif k == 'ht':
482 htcaps.add('') # NB: ensure 802.11n setup below
483 elif k == 'htprotmode':
484 pass # TODO(sleffler) need hostapd support
485 elif k == 'rifs':
486 pass # TODO(sleffler) need hostapd support
487 elif k == 'wepmode':
488 pass # NB: meaningless for hostapd; ignore
489 elif k == '-ampdu':
490 pass # TODO(sleffler) need hostapd support
491 elif k == 'txpower':
492 tx_power_params['power'] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700493 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800494 conf[k] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700495
Paul Stewartc2b3de82011-03-03 14:45:31 -0800496 # Aggregate ht_capab.
497 if htcaps:
498 conf['ieee80211n'] = 1
499 conf['ht_capab'] = ''.join(htcaps)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700500
Paul Stewart548cf452012-11-27 17:46:23 -0800501 self.start_hostapd(conf, orig_params)
Paul Stewart1ae854b2011-02-08 15:10:14 -0800502
Paul Stewartc2b3de82011-03-03 14:45:31 -0800503 # Configure transmit power
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700504 tx_power_params['interface'] = conf['interface']
Paul Stewartc2b3de82011-03-03 14:45:31 -0800505 self.set_txpower(tx_power_params)
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700506
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700507 if self.force_local_server or local_server is not False:
508 self.start_local_server(conf['interface'])
Sam Leffler6969d1d2010-03-15 16:07:11 -0700509
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700510 self._post_start_hook(orig_params)
511
512 logging.info("AP configured.")
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700513 self.hostapd['configured'] = True
Sam Leffler6969d1d2010-03-15 16:07:11 -0700514
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700515
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700516 @staticmethod
517 def ip_addr(netblock, idx):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700518 """Simple IPv4 calculator.
519
520 Takes host address in "IP/bits" notation and returns netmask, broadcast
521 address as well as integer offsets into the address range.
522
523 @param netblock string host address in "IP/bits" notation.
524 @param idx string describing what to return.
525 @return string containing something you hopefully requested.
526
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700527 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700528 addr_str,bits = netblock.split('/')
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700529 addr = map(int, addr_str.split('.'))
530 mask_bits = (-1 << (32-int(bits))) & 0xffffffff
531 mask = [(mask_bits >> s) & 0xff for s in range(24, -1, -8)]
Paul Stewart5977da92011-06-01 19:14:08 -0700532 if idx == 'local':
533 return addr_str
534 elif idx == 'netmask':
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700535 return '.'.join(map(str, mask))
536 elif idx == 'broadcast':
537 offset = [m ^ 0xff for m in mask]
538 else:
539 offset = [(idx >> s) & 0xff for s in range(24, -1, -8)]
540 return '.'.join(map(str, [(a & m) + o
541 for a, m, o in zip(addr, mask, offset)]))
542
543
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700544 def ibss_configure(self, config):
545 """Configure a station based AP in IBSS mode.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700546
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700547 Extract relevant configuration objects from |config| despite not
548 actually being a hostap managed endpoint.
549
550 @param config HostapConfig object.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700551
552 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700553 if self.station['configured'] or self.hostapd['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700554 self.deconfig()
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700555 interface = self._get_wlanif(config.frequency, self.phytype,
556 config.hw_mode)
Christopher Wiley3166e432013-08-06 09:53:12 -0700557 self.station['conf']['ssid'] = (config.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700558 self._build_ssid(config.ssid_suffix))
Paul Stewartc2b3de82011-03-03 14:45:31 -0800559 # Connect the station
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700560 self.router.run('%s link set %s up' % (self.cmd_ip, interface))
Christopher Wiley3166e432013-08-06 09:53:12 -0700561 self.router.run('%s dev %s ibss join %s %d' % (
562 self.cmd_iw, interface, self.station['conf']['ssid'],
563 config.frequency))
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700564 # Always start a local server.
565 self.start_local_server(interface)
566 # Remember that this interface is up.
Paul Stewartc2b3de82011-03-03 14:45:31 -0800567 self.station['configured'] = True
568 self.station['interface'] = interface
569
570
Paul Stewart2bd823b2012-11-21 15:03:37 -0800571 def local_server_address(self, index):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700572 """Get the local server address for an interface.
573
574 When we multiple local servers, we give them static IP addresses
575 like 192.158.*.254.
576
577 @param index int describing which local server this is for.
578
579 """
Paul Stewart2bd823b2012-11-21 15:03:37 -0800580 return '%d.%d.%d.%d' % (192, 168, index, 254)
581
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700582
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700583 def start_local_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700584 """Start a local server on an interface.
585
586 @param interface string (e.g. wlan0)
587
588 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700589 logging.info("Starting up local server...")
590
591 if len(self.local_servers) >= 256:
592 raise error.TestFail('Exhausted available local servers')
593
Paul Stewart2bd823b2012-11-21 15:03:37 -0800594 netblock = '%s/24' % self.local_server_address(len(self.local_servers))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700595
596 params = {}
597 params['netblock'] = netblock
598 params['subnet'] = self.ip_addr(netblock, 0)
599 params['netmask'] = self.ip_addr(netblock, 'netmask')
600 params['dhcp_range'] = ' '.join(
601 (self.ip_addr(netblock, self.dhcp_low),
602 self.ip_addr(netblock, self.dhcp_high)))
mukesh agrawal05c455a2011-10-12 13:40:27 -0700603 params['interface'] = interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700604
605 params['ip_params'] = ("%s broadcast %s dev %s" %
606 (netblock,
607 self.ip_addr(netblock, 'broadcast'),
608 interface))
609 self.local_servers.append(params)
610
611 self.router.run("%s addr flush %s" %
612 (self.cmd_ip, interface))
613 self.router.run("%s addr add %s" %
614 (self.cmd_ip, params['ip_params']))
615 self.router.run("%s link set %s up" %
616 (self.cmd_ip, interface))
Paul Stewart548cf452012-11-27 17:46:23 -0800617 self.start_dhcp_server(interface)
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700618
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700619
Paul Stewart548cf452012-11-27 17:46:23 -0800620 def start_dhcp_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700621 """Start a dhcp server on an interface.
622
623 @param interface string (e.g. wlan0)
624
625 """
Paul Stewart326badb2012-12-18 14:18:54 -0800626 conf_file = self.dhcpd_conf % interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700627 dhcp_conf = '\n'.join(map(
628 lambda server_conf: \
629 "subnet %(subnet)s netmask %(netmask)s {\n" \
630 " range %(dhcp_range)s;\n" \
631 "}" % server_conf,
632 self.local_servers))
633 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
Paul Stewart326badb2012-12-18 14:18:54 -0800634 (conf_file,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700635 '\n'.join(('ddns-update-style none;', dhcp_conf))))
636 self.router.run("touch %s" % self.dhcpd_leases)
637
638 self.router.run("pkill dhcpd >/dev/null 2>&1", ignore_status=True)
639 self.router.run("%s -q -cf %s -lf %s" %
Paul Stewart326badb2012-12-18 14:18:54 -0800640 (self.cmd_dhcpd, conf_file, self.dhcpd_leases))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700641
642
Paul Stewart326badb2012-12-18 14:18:54 -0800643 def stop_dhcp_server(self, instance=None):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700644 """Stop a dhcp server on the router.
645
646 @param instance string instance to kill.
647
648 """
Paul Stewart326badb2012-12-18 14:18:54 -0800649 self._kill_process_instance('dhcpd', instance, 0)
650
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700651
Paul Stewart548cf452012-11-27 17:46:23 -0800652 def stop_dhcp_servers(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700653 """Stop all dhcp servers on the router."""
Paul Stewart326badb2012-12-18 14:18:54 -0800654 self.stop_dhcp_server(None)
Paul Stewart548cf452012-11-27 17:46:23 -0800655
656
Paul Stewartc2b3de82011-03-03 14:45:31 -0800657 def config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700658 """Configure an AP based on site_wifitest parameters.
659
660 @param params dict of site_wifitest parameters.
661
662 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800663 if self.apmode:
664 self.hostap_config(params)
665 else:
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700666 config = hostap_config.HostapConfig(
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700667 frequency=int(params.get('channel', None)))
668 self.ibss_configure(config)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800669
670
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700671 def get_wifi_ip(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700672 """Return IP address on the WiFi subnet of a local server on the router.
673
674 If no local servers are configured (e.g. for an RSPro), a TestFail will
675 be raised.
676
677 @param ap_num int which local server to get an address from.
678
679 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700680 if self.local_servers:
681 return self.ip_addr(self.local_servers[ap_num]['netblock'],
682 'local')
683 else:
684 raise error.TestFail("No IP address assigned")
Paul Stewart5977da92011-06-01 19:14:08 -0700685
686
Paul Stewart17350be2012-12-14 13:34:54 -0800687 def get_hostapd_mac(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700688 """Return the MAC address of an AP in the test.
689
690 @param ap_num int index of local server to read the MAC address from.
691 @return string MAC address like 00:11:22:33:44:55.
692
693 """
Paul Stewart17350be2012-12-14 13:34:54 -0800694 instance = self.hostapd_instances[ap_num]
695 interface = instance['interface']
696 result = self.router.run('%s addr show %s' % (self.cmd_ip, interface))
697 # Example response:
698 # 1: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 UP qlen 1000
699 # link/ether 99:88:77:66:55:44 brd ff:ff:ff:ff:ff:ff
700 # inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
701 # inet6 fe80::6a7f:74ff:fe66:5544/64 scope link
702 # we want the MAC address after the "link/ether" above.
703 parts = result.stdout.split(' ')
704 return parts[parts.index('link/ether') + 1]
705
706
Christopher Wileyd89b5282013-04-10 15:21:26 -0700707 def deconfig(self, params={}):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700708 """De-configure the AP (will also bring wlan down).
Sam Leffler6969d1d2010-03-15 16:07:11 -0700709
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700710 @param params dict of parameters from site_wifitest.
711
712 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800713 if not self.hostapd['configured'] and not self.station['configured']:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700714 return
Sam Leffler6969d1d2010-03-15 16:07:11 -0700715
Paul Stewartc2b3de82011-03-03 14:45:31 -0800716 if self.hostapd['configured']:
Paul Stewart326badb2012-12-18 14:18:54 -0800717 local_servers = []
Paul Stewart21737812012-12-06 11:03:32 -0800718 if 'instance' in params:
719 instances = [ self.hostapd_instances.pop(params['instance']) ]
Paul Stewart326badb2012-12-18 14:18:54 -0800720 for server in self.local_servers:
721 if server['interface'] == instances[0]['interface']:
722 local_servers = [server]
723 self.local_servers.remove(server)
724 break
Paul Stewart21737812012-12-06 11:03:32 -0800725 else:
726 instances = self.hostapd_instances
727 self.hostapd_instances = []
Paul Stewart326badb2012-12-18 14:18:54 -0800728 local_servers = self.local_servers
729 self.local_servers = []
Paul Stewart64cc4292011-06-01 10:59:36 -0700730
Paul Stewart21737812012-12-06 11:03:32 -0800731 for instance in instances:
732 if 'silent' in params:
733 # Deconfigure without notifying DUT. Remove the interface
734 # hostapd uses to send beacon and DEAUTH packets.
735 self._remove_interface(instance['interface'], True)
736
Paul Stewart326badb2012-12-18 14:18:54 -0800737 self.kill_hostapd_instance(instance['conf_file'])
Paul Stewart548cf452012-11-27 17:46:23 -0800738 self.router.get_file(instance['log_file'],
739 'debug/hostapd_router_%d_%s.log' %
740 (self.hostapd['log_count'],
741 instance['interface']))
742 self._release_wlanif(instance['interface'])
743# self.router.run("rm -f %(log_file)s %(conf_file)s" % instance)
Paul Stewartf854d2e2011-05-04 13:19:18 -0700744 self.hostapd['log_count'] += 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800745 if self.station['configured']:
Christopher Wiley05262d62013-04-17 17:53:59 -0700746 local_servers = self.local_servers
747 self.local_servers = []
Paul Stewartc2b3de82011-03-03 14:45:31 -0800748 if self.station['type'] == 'ibss':
749 self.router.run("%s dev %s ibss leave" %
750 (self.cmd_iw, self.station['interface']))
751 else:
752 self.router.run("%s dev %s disconnect" %
753 (self.cmd_iw, self.station['interface']))
754 self.router.run("%s link set %s down" % (self.cmd_ip,
755 self.station['interface']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700756
Paul Stewart326badb2012-12-18 14:18:54 -0800757 for server in local_servers:
758 self.stop_dhcp_server(server['interface'])
759 self.router.run("%s addr del %s" %
760 (self.cmd_ip, server['ip_params']),
761 ignore_status=True)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700762
763 self.hostapd['configured'] = False
Paul Stewartc2b3de82011-03-03 14:45:31 -0800764 self.station['configured'] = False
Paul Stewart7cb1f062010-06-10 15:46:20 -0700765
766
Paul Stewart17350be2012-12-14 13:34:54 -0800767 def verify_pmksa_auth(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700768 """Verify that the PMKSA auth was cached on a hostapd instance.
769
770 @param params dict with optional key 'instance' (defaults to 0).
771
772 """
Paul Stewart17350be2012-12-14 13:34:54 -0800773 instance_num = params.get('instance', 0)
774 instance = self.hostapd_instances[instance_num]
775 pmksa_match = 'PMK from PMKSA cache - skip IEEE 802.1X.EAP'
776 self.router.run('grep -q "%s" %s' % (pmksa_match, instance['log_file']))
777
778
Paul Stewart7cb1f062010-06-10 15:46:20 -0700779 def get_ssid(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700780 """@return string ssid for the network stemming from this router."""
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700781 if self.hostapd['configured']:
782 return self.hostapd['conf']['ssid']
783
Christopher Wiley3166e432013-08-06 09:53:12 -0700784 if not 'ssid' in self.station['conf']:
785 raise error.TestFail('Requested ssid of an unconfigured AP.')
786
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700787 return self.station['conf']['ssid']
Paul Stewart98022e22010-10-22 10:33:14 -0700788
789
790 def set_txpower(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700791 """Set the transmission power for an interface.
792
793 Assumes that we want to refer to the first hostapd instance unless
794 'interface' is defined in params. Sets the transmission power to
795 'auto' if 'power' is not defined in params.
796
797 @param params dict of parameters as described above.
798
799 """
Paul Stewart548cf452012-11-27 17:46:23 -0800800 interface = params.get('interface',
801 self.hostapd_instances[0]['interface'])
802 power = params.get('power', 'auto')
Paul Stewart98022e22010-10-22 10:33:14 -0700803 self.router.run("%s dev %s set txpower %s" %
Paul Stewart548cf452012-11-27 17:46:23 -0800804 (self.cmd_iw, interface, power))
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700805
806
807 def deauth(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700808 """Deauthenticates a client described in params.
809
810 @param params dict containing a key 'client'.
811
812 """
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700813 self.router.run('%s -p%s deauthenticate %s' %
814 (self.cmd_hostapd_cli,
815 self.hostapd['conf']['ctrl_interface'],
816 params['client']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700817
818
Paul Stewart51b0f382013-06-12 09:03:02 -0700819 def send_management_frame(self, frame_type, instance=0):
820 """Injects a management frame into an active hostapd session.
821
822 @param frame_type string the type of frame to send.
823 @param instance int indicating which hostapd instance to inject into.
824
825 """
826 hostap_interface = self.hostapd_instances[instance]['interface']
827 interface = self._get_wlanif(0, 'monitor', same_phy_as=hostap_interface)
828 self.router.run("%s link set %s up" % (self.cmd_ip, interface))
829 self.router.run('%s %s %s' %
830 (self.cmd_send_management_frame, interface, frame_type))
831 self._release_wlanif(interface)
832
833
Paul Stewart25536942013-08-15 17:33:42 -0700834 def detect_client_deauth(self, client_mac, instance=0):
835 """Detects whether hostapd has logged a deauthentication from
836 |client_mac|.
837
838 @param client_mac string the MAC address of the client to detect.
839 @param instance int indicating which hostapd instance to query.
840
841 """
842 interface = self.hostapd_instances[instance]['interface']
843 deauth_msg = "%s: deauthentication: STA=%s" % (interface, client_mac)
844 log_file = self.hostapd_instances[instance]['log_file']
845 result = self.router.run("grep -qi '%s' %s" % (deauth_msg, log_file),
846 ignore_status=True)
847 return result.exit_status == 0
848
849
Paul Stewart4ae471e2013-09-04 15:42:35 -0700850 def detect_client_coexistence_report(self, client_mac, instance=0):
851 """Detects whether hostapd has logged an action frame from
852 |client_mac| indicating information about 20/40MHz BSS coexistence.
853
854 @param client_mac string the MAC address of the client to detect.
855 @param instance int indicating which hostapd instance to query.
856
857 """
858 coex_msg = ('nl80211: MLME event frame - hexdump(len=.*): '
859 '.. .. .. .. .. .. .. .. .. .. %s '
860 '.. .. .. .. .. .. .. .. 04 00.*48 01 ..' %
861 ' '.join(client_mac.split(':')))
862 log_file = self.hostapd_instances[instance]['log_file']
863 result = self.router.run("grep -qi '%s' %s" % (coex_msg, log_file),
864 ignore_status=True)
865 return result.exit_status == 0
866
867
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700868 def _pre_config_hook(self, config):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700869 """Hook for subclasses.
870
871 Run after gathering configuration parameters,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700872 but before writing parameters to config file.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700873
874 @param config dict containing hostapd config parameters.
875
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700876 """
877 pass
878
879
880 def _pre_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700881 """Hook for subclasses.
882
883 Run after generating hostapd config file, but before starting hostapd.
884
885 @param params dict parameters from site_wifitest.
886
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700887 """
888 pass
889
890
891 def _post_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700892 """Hook for subclasses run after starting hostapd.
893
894 @param params dict parameters from site_wifitest.
895
896 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700897 pass