blob: 19b0fa079a3c7edbca7094895fd45d1e34ac0742 [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
Christopher Wileyb1ade0a2013-09-16 13:09:55 -070042 SUBNET_PREFIX_OCTETS = (192, 168)
Sam Leffler6969d1d2010-03-15 16:07:11 -070043
Paul Stewart51b0f382013-06-12 09:03:02 -070044 def get_capabilities(self):
45 """@return iterable object of AP capabilities for this system."""
46 caps = set()
47 try:
48 self.cmd_send_management_frame = wifi_test_utils.must_be_installed(
49 self.router, '/usr/bin/send_management_frame')
50 caps.add(self.CAPABILITY_SEND_MANAGEMENT_FRAME)
51 except error.TestFail:
52 pass
53 return super(LinuxRouter, self).get_capabilities().union(caps)
54
55
Christopher Wiley3166e432013-08-06 09:53:12 -070056 def __init__(self, host, params, test_name):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070057 """Build a LinuxRouter.
58
59 @param host Host object representing the remote machine.
60 @param params dict of settings from site_wifitest based tests.
Christopher Wiley3166e432013-08-06 09:53:12 -070061 @param test_name string name of this test. Used in SSID creation.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070062
63 """
64 site_linux_system.LinuxSystem.__init__(self, host, params, 'router')
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070065 self._remove_interfaces()
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070066
Wade Guthrie24d1e312012-04-24 16:53:40 -070067 # Router host.
68 self.router = host
69
Christopher Wiley4bca01e2013-09-13 13:36:39 -070070 self.cmd_dhcpd = params.get('cmd_dhcpd', '/usr/sbin/dhcpd')
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070071 self.cmd_hostapd = wifi_test_utils.must_be_installed(
72 host, params.get('cmd_hostapd', '/usr/sbin/hostapd'))
73 self.cmd_hostapd_cli = params.get('cmd_hostapd_cli',
74 '/usr/sbin/hostapd_cli')
75 self.dhcpd_conf = '/tmp/dhcpd.%s.conf'
76 self.dhcpd_leases = '/tmp/dhcpd.leases'
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070077
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070078 # hostapd configuration persists throughout the test, subsequent
79 # 'config' commands only modify it.
Christopher Wiley3166e432013-08-06 09:53:12 -070080 self.ssid_prefix = test_name
81 if self.ssid_prefix.startswith(self.KNOWN_TEST_PREFIX):
82 # Many of our tests start with an uninteresting prefix.
83 # Remove it so we can have more unique bytes.
84 self.ssid_prefix = self.ssid_prefix[len(self.KNOWN_TEST_PREFIX):]
85 self.ssid_prefix = self.ssid_prefix.lstrip('_')
86 self.ssid_prefix += '_'
87
Paul Stewartd5aafa92013-03-24 19:06:14 -070088 self.default_config = {
Paul Stewartd5aafa92013-03-24 19:06:14 -070089 'hw_mode': 'g',
90 'ctrl_interface': '/tmp/hostapd-test.control',
91 'logger_syslog': '-1',
92 'logger_syslog_level': '0'
93 }
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070094 self.hostapd = {
95 'configured': False,
Paul Stewart326badb2012-12-18 14:18:54 -080096 'config_file': "/tmp/hostapd-test-%s.conf",
97 'log_file': "/tmp/hostapd-test-%s.log",
Christopher Wiley1defc242013-09-18 10:28:37 -070098 'pid_file': "/tmp/hostapd-test-%s.pid",
Paul Stewartf854d2e2011-05-04 13:19:18 -070099 'log_count': 0,
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700100 'driver': "nl80211",
Paul Stewartd5aafa92013-03-24 19:06:14 -0700101 'conf': self.default_config.copy()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700102 }
Paul Stewartc2b3de82011-03-03 14:45:31 -0800103 self.station = {
104 'configured': False,
Christopher Wiley3166e432013-08-06 09:53:12 -0700105 'conf': {},
Paul Stewartc2b3de82011-03-03 14:45:31 -0800106 }
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700107 self.local_servers = []
Paul Stewart548cf452012-11-27 17:46:23 -0800108 self.hostapd_instances = []
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700109 self.force_local_server = "force_local_server" in params
110 self.dhcp_low = 1
111 self.dhcp_high = 128
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700112
Paul Stewart548cf452012-11-27 17:46:23 -0800113 # Kill hostapd and dhcp server if already running.
Thieu Le7b23a542012-01-27 15:54:48 -0800114 self.kill_hostapd()
Paul Stewart548cf452012-11-27 17:46:23 -0800115 self.stop_dhcp_servers()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700116
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -0700117 # Place us in the US by default
118 self.router.run("%s reg set US" % self.cmd_iw)
Sam Leffler6969d1d2010-03-15 16:07:11 -0700119
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700120
Christopher Wileyf4bc88b2013-08-29 16:45:15 -0700121 def close(self):
122 """Close global resources held by this system."""
123 self.destroy()
124 super(LinuxRouter, self).close()
125
126
Sam Leffler6969d1d2010-03-15 16:07:11 -0700127 def create(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700128 """Create a wifi device of the specified type.
Christopher Wiley14796b32013-04-03 14:53:33 -0700129
130 @param params dict containing the device type under key 'type'.
131
132 """
133 self.create_wifi_device(params['type'])
134
135
136 def create_wifi_device(self, device_type='hostap'):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700137 """Create a wifi device of the specified type.
Christopher Wiley14796b32013-04-03 14:53:33 -0700138
139 Defaults to creating a hostap managed device.
140
141 @param device_type string device type.
142
143 """
Sam Leffler6969d1d2010-03-15 16:07:11 -0700144 #
145 # AP mode is handled entirely by hostapd so we only
146 # have to setup others (mapping the bsd type to what
147 # iw wants)
148 #
149 # map from bsd types to iw types
Christopher Wiley14796b32013-04-03 14:53:33 -0700150 self.apmode = device_type in ('ap', 'hostap')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800151 if not self.apmode:
Christopher Wiley14796b32013-04-03 14:53:33 -0700152 self.station['type'] = device_type
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700153 self.phytype = {
Christopher Wiley14796b32013-04-03 14:53:33 -0700154 'sta' : 'managed',
155 'monitor' : 'monitor',
156 'adhoc' : 'adhoc',
157 'ibss' : 'ibss',
158 'ap' : 'managed', # NB: handled by hostapd
159 'hostap' : 'managed', # NB: handled by hostapd
160 'mesh' : 'mesh',
161 'wds' : 'wds',
162 }[device_type]
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700163
Sam Leffler6969d1d2010-03-15 16:07:11 -0700164
Christopher Wileyd89b5282013-04-10 15:21:26 -0700165 def destroy(self, params={}):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700166 """Destroy a previously created device.
167
168 @param params dict of site_wifitest parameters.
169
170 """
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700171 self.deconfig(params)
Paul Stewartd5aafa92013-03-24 19:06:14 -0700172 self.hostapd['conf'] = self.default_config.copy()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700173
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700174
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700175 def has_local_server(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700176 """@return True iff this router has local servers configured."""
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700177 return bool(self.local_servers)
Sam Leffler6969d1d2010-03-15 16:07:11 -0700178
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700179
Paul Stewart9e3ff0b2011-08-17 20:35:19 -0700180 def cleanup(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700181 """Clean up any resources in use.
182
183 @param params dict of site_wifitest parameters.
184
185 """
Paul Stewart9e3ff0b2011-08-17 20:35:19 -0700186 # For linux, this is a no-op
187 pass
188
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700189
Paul Stewart548cf452012-11-27 17:46:23 -0800190 def start_hostapd(self, conf, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700191 """Start a hostapd instance described by conf.
192
193 @param conf dict of hostapd configuration parameters.
194 @param params dict of site_wifitest parameters.
195
196 """
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700197 logging.info('Starting hostapd with parameters: %r', conf)
Paul Stewart548cf452012-11-27 17:46:23 -0800198 # Figure out the correct interface.
Paul Stewart326badb2012-12-18 14:18:54 -0800199 interface = self._get_wlanif(self.hostapd['frequency'],
200 self.phytype,
201 mode=conf.get('hw_mode', 'b'))
202
203 conf_file = self.hostapd['config_file'] % interface
204 log_file = self.hostapd['log_file'] % interface
Christopher Wiley1defc242013-09-18 10:28:37 -0700205 pid_file = self.hostapd['pid_file'] % interface
Paul Stewart326badb2012-12-18 14:18:54 -0800206 conf['interface'] = interface
Paul Stewart548cf452012-11-27 17:46:23 -0800207
208 # Generate hostapd.conf.
209 self._pre_config_hook(conf)
210 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
211 (conf_file, '\n'.join(
212 "%s=%s" % kv for kv in conf.iteritems())))
213
214 # Run hostapd.
215 logging.info("Starting hostapd...")
Christopher Wiley1defc242013-09-18 10:28:37 -0700216 self.router.run('rm %s' % log_file, ignore_status=True)
217 self.router.run('rm %s' % pid_file, ignore_status=True)
Paul Stewart548cf452012-11-27 17:46:23 -0800218 self._pre_start_hook(params)
Christopher Wiley1defc242013-09-18 10:28:37 -0700219 self.router.run("%s -dd -B -t -f %s -P %s %s" %
220 (self.cmd_hostapd, log_file, pid_file, conf_file))
221 pid = int(self.router.run('cat %s' % pid_file).stdout)
222
223 # Wait for confirmation that the router came up.
224 logging.info('Waiting for hostapd to startup.')
225 start_time = time.time()
226 while time.time() - start_time < self.STARTUP_TIMEOUT_SECONDS:
227 success = self.router.run(
228 'grep "Completing interface initialization" %s' % log_file,
229 ignore_status=True).exit_status == 0
230 if success:
231 break
232
233 # A common failure is to request an invalid router configuration.
234 # Detect this and exit early if we see it.
235 bad_config = self.router.run(
236 'grep "Interface initialization failed" %s' % log_file,
237 ignore_status=True).exit_status == 0
238 if bad_config:
239 raise error.TestFail('hostapd failed to initialize AP '
240 'interface.')
241
242 early_exit = self.router.run('kill -0 %d' % pid,
243 ignore_status=True).exit_status
244 if early_exit:
245 raise error.TestFail('hostapd process terminated.')
246
247 time.sleep(self.STARTUP_POLLING_INTERVAL_SECONDS)
248 else:
249 raise error.TestFail('Timed out while waiting for hostapd '
250 'to start.')
Paul Stewart548cf452012-11-27 17:46:23 -0800251
252 self.hostapd_instances.append({
253 'conf_file': conf_file,
254 'log_file': log_file,
Christopher Wiley1defc242013-09-18 10:28:37 -0700255 'interface': interface,
256 'pid_file': pid_file
Paul Stewart548cf452012-11-27 17:46:23 -0800257 })
258
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700259
Paul Stewart326badb2012-12-18 14:18:54 -0800260 def _kill_process_instance(self, process, instance=None, wait=0):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700261 """Kill a process on the router.
262
Paul Stewart326badb2012-12-18 14:18:54 -0800263 Kills program named |process|, optionally only a specific
264 |instance|. If |wait| is specified, we makes sure |process| exits
265 before returning.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700266
267 @param process string name of process to kill.
268 @param instance string instance of process to kill.
269 @param wait int timeout in seconds to wait for.
270
Thieu Le7b23a542012-01-27 15:54:48 -0800271 """
Paul Stewart21737812012-12-06 11:03:32 -0800272 if instance:
Paul Stewart326badb2012-12-18 14:18:54 -0800273 search_arg = '-f "%s.*%s"' % (process, instance)
Paul Stewart21737812012-12-06 11:03:32 -0800274 else:
Paul Stewart326badb2012-12-18 14:18:54 -0800275 search_arg = process
Paul Stewart21737812012-12-06 11:03:32 -0800276
Paul Stewart326badb2012-12-18 14:18:54 -0800277 cmd = "pkill %s >/dev/null 2>&1" % search_arg
278
279 if wait:
280 cmd += (" && while pgrep %s &> /dev/null; do sleep 1; done" %
281 search_arg)
282 self.router.run(cmd, timeout=wait, ignore_status=True)
283 else:
284 self.router.run(cmd, ignore_status=True)
285
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700286
Paul Stewart326badb2012-12-18 14:18:54 -0800287 def kill_hostapd_instance(self, instance):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700288 """Kills a hostapd instance.
289
290 @param instance string instance to kill.
291
292 """
Paul Stewart326badb2012-12-18 14:18:54 -0800293 self._kill_process_instance('hostapd', instance, 30)
Thieu Le7b23a542012-01-27 15:54:48 -0800294
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700295
Paul Stewart21737812012-12-06 11:03:32 -0800296 def kill_hostapd(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700297 """Kill all hostapd instances."""
Paul Stewart21737812012-12-06 11:03:32 -0800298 self.kill_hostapd_instance(None)
299
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700300
301 def __get_default_hostap_config(self):
302 """@return dict of default options for hostapd."""
303 conf = self.hostapd['conf']
304 # default RTS and frag threshold to ``off''
305 conf['rts_threshold'] = '2347'
306 conf['fragm_threshold'] = '2346'
307 conf['driver'] = self.hostapd['driver']
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700308 conf['ssid'] = self._build_ssid('')
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700309 return conf
310
311
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700312 def _build_ssid(self, suffix):
Christopher Wiley3166e432013-08-06 09:53:12 -0700313 unique_salt = ''.join([random.choice(self.SUFFIX_LETTERS)
314 for x in range(5)])
315 return (self.ssid_prefix + unique_salt + suffix)[-32:]
316
317
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700318 def hostap_configure(self, configuration, multi_interface=None):
319 """Build up a hostapd configuration file and start hostapd.
320
321 Also setup a local server if this router supports them.
322
323 @param configuration HosetapConfig object.
324 @param multi_interface bool True iff multiple interfaces allowed.
325
326 """
327 if multi_interface is None and (self.hostapd['configured'] or
328 self.station['configured']):
329 self.deconfig()
330 # Start with the default hostapd config parameters.
331 conf = self.__get_default_hostap_config()
Christopher Wiley3166e432013-08-06 09:53:12 -0700332 conf['ssid'] = (configuration.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700333 self._build_ssid(configuration.ssid_suffix))
Christopher Wiley9b406202013-05-06 14:07:49 -0700334 if configuration.bssid:
335 conf['bssid'] = configuration.bssid
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700336 conf['channel'] = configuration.channel
337 self.hostapd['frequency'] = configuration.frequency
338 conf['hw_mode'] = configuration.hw_mode
339 if configuration.hide_ssid:
340 conf['ignore_broadcast_ssid'] = 1
341 if configuration.is_11n:
342 conf['ieee80211n'] = 1
Christopher Wiley32fbb7a2013-09-18 14:30:50 -0700343 conf['ht_capab'] = configuration.hostapd_ht_capabilities
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700344 if configuration.wmm_enabled:
345 conf['wmm_enabled'] = 1
346 if configuration.require_ht:
347 conf['require_ht'] = 1
Christopher Wiley9fa7c632013-05-01 11:58:06 -0700348 if configuration.beacon_interval:
349 conf['beacon_int'] = configuration.beacon_interval
Christopher Wileya51258e2013-05-03 13:05:06 -0700350 if configuration.dtim_period:
351 conf['dtim_period'] = configuration.dtim_period
Christopher Wileye1235b62013-05-03 15:09:34 -0700352 if configuration.frag_threshold:
353 conf['fragm_threshold'] = configuration.frag_threshold
Christopher Wileyebdc27d2013-06-28 14:35:41 -0700354 if configuration.pmf_support:
355 conf['ieee80211w'] = configuration.pmf_support
Paul Stewart4ae471e2013-09-04 15:42:35 -0700356 if configuration.obss_interval:
357 conf['obss_interval'] = configuration.obss_interval
Christopher Wileyb8921c72013-06-13 09:51:47 -0700358 conf.update(configuration.get_security_hostapd_conf())
Christopher Wileya89706d2013-06-12 13:20:58 -0700359
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700360 self.start_hostapd(conf, {})
361 # Configure transmit power
362 tx_power_params = {'interface': conf['interface']}
363 # TODO(wiley) support for setting transmit power
364 self.set_txpower(tx_power_params)
365 if self.force_local_server:
366 self.start_local_server(conf['interface'])
367 self._post_start_hook({})
368 logging.info('AP configured.')
369 self.hostapd['configured'] = True
370
371
Paul Stewartc2b3de82011-03-03 14:45:31 -0800372 def hostap_config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700373 """Configure the AP per test requirements.
Sam Leffler6969d1d2010-03-15 16:07:11 -0700374
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700375 @param params dict of site_wifitest parameters.
376
377 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700378 # keep parameter modifications local-only
379 orig_params = params
380 params = params.copy()
381
Paul Stewart45338d22010-10-21 10:57:02 -0700382 multi_interface = 'multi_interface' in params
383 if multi_interface:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700384 # remove non-hostapd config item from params
Paul Stewart45338d22010-10-21 10:57:02 -0700385 params.pop('multi_interface')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800386 elif self.hostapd['configured'] or self.station['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700387 self.deconfig()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700388
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700389 local_server = params.pop('local_server', False)
390
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700391 conf = self.__get_default_hostap_config()
Paul Stewartc2b3de82011-03-03 14:45:31 -0800392 tx_power_params = {}
393 htcaps = set()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700394
Paul Stewartc2b3de82011-03-03 14:45:31 -0800395 for k, v in params.iteritems():
396 if k == 'ssid':
397 conf['ssid'] = v
398 elif k == 'ssid_suffix':
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700399 conf['ssid'] = self._build_ssid(v)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800400 elif k == 'channel':
401 freq = int(v)
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700402 self.hostapd['frequency'] = freq
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700403
Paul Stewartc2b3de82011-03-03 14:45:31 -0800404 # 2.4GHz
405 if freq <= 2484:
406 # Make sure hw_mode is set
407 if conf.get('hw_mode') == 'a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700408 conf['hw_mode'] = 'g'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800409
410 # Freq = 5 * chan + 2407, except channel 14
411 if freq == 2484:
412 conf['channel'] = 14
413 else:
414 conf['channel'] = (freq - 2407) / 5
415 # 5GHz
Sam Leffler6969d1d2010-03-15 16:07:11 -0700416 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800417 # Make sure hw_mode is set
418 conf['hw_mode'] = 'a'
419 # Freq = 5 * chan + 4000
420 if freq < 5000:
421 conf['channel'] = (freq - 4000) / 5
422 # Freq = 5 * chan + 5000
423 else:
424 conf['channel'] = (freq - 5000) / 5
Sam Leffler6969d1d2010-03-15 16:07:11 -0700425
Paul Stewartc2b3de82011-03-03 14:45:31 -0800426 elif k == 'country':
427 conf['country_code'] = v
428 elif k == 'dotd':
429 conf['ieee80211d'] = 1
430 elif k == '-dotd':
431 conf['ieee80211d'] = 0
432 elif k == 'mode':
433 if v == '11a':
434 conf['hw_mode'] = 'a'
435 elif v == '11g':
436 conf['hw_mode'] = 'g'
437 elif v == '11b':
438 conf['hw_mode'] = 'b'
439 elif v == '11n':
440 conf['ieee80211n'] = 1
441 elif k == 'bintval':
442 conf['beacon_int'] = v
443 elif k == 'dtimperiod':
444 conf['dtim_period'] = v
445 elif k == 'rtsthreshold':
446 conf['rts_threshold'] = v
447 elif k == 'fragthreshold':
448 conf['fragm_threshold'] = v
449 elif k == 'shortpreamble':
450 conf['preamble'] = 1
451 elif k == 'authmode':
452 if v == "open":
453 conf['auth_algs'] = 1
454 elif v == "shared":
455 conf['auth_algs'] = 2
456 elif k == 'hidessid':
457 conf['ignore_broadcast_ssid'] = 1
458 elif k == 'wme':
459 conf['wmm_enabled'] = 1
460 elif k == '-wme':
461 conf['wmm_enabled'] = 0
462 elif k == 'deftxkey':
463 conf['wep_default_key'] = v
464 elif k == 'ht20':
465 htcaps.add('') # NB: ensure 802.11n setup below
466 conf['wmm_enabled'] = 1
467 elif k == 'ht40':
468 htcaps.add('[HT40-]')
469 htcaps.add('[HT40+]')
470 conf['wmm_enabled'] = 1
Paul Stewartc1df8d62011-04-07 14:28:15 -0700471 elif k in ('ht40+', 'ht40-'):
472 htcaps.add('[%s]' % k.upper())
473 conf['wmm_enabled'] = 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800474 elif k == 'shortgi':
475 htcaps.add('[SHORT-GI-20]')
476 htcaps.add('[SHORT-GI-40]')
477 elif k == 'pureg':
478 pass # TODO(sleffler) need hostapd support
479 elif k == 'puren':
480 pass # TODO(sleffler) need hostapd support
481 elif k == 'protmode':
482 pass # TODO(sleffler) need hostapd support
483 elif k == 'ht':
484 htcaps.add('') # NB: ensure 802.11n setup below
485 elif k == 'htprotmode':
486 pass # TODO(sleffler) need hostapd support
487 elif k == 'rifs':
488 pass # TODO(sleffler) need hostapd support
489 elif k == 'wepmode':
490 pass # NB: meaningless for hostapd; ignore
491 elif k == '-ampdu':
492 pass # TODO(sleffler) need hostapd support
493 elif k == 'txpower':
494 tx_power_params['power'] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700495 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800496 conf[k] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700497
Paul Stewartc2b3de82011-03-03 14:45:31 -0800498 # Aggregate ht_capab.
499 if htcaps:
500 conf['ieee80211n'] = 1
501 conf['ht_capab'] = ''.join(htcaps)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700502
Paul Stewart548cf452012-11-27 17:46:23 -0800503 self.start_hostapd(conf, orig_params)
Paul Stewart1ae854b2011-02-08 15:10:14 -0800504
Paul Stewartc2b3de82011-03-03 14:45:31 -0800505 # Configure transmit power
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700506 tx_power_params['interface'] = conf['interface']
Paul Stewartc2b3de82011-03-03 14:45:31 -0800507 self.set_txpower(tx_power_params)
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700508
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700509 if self.force_local_server or local_server is not False:
510 self.start_local_server(conf['interface'])
Sam Leffler6969d1d2010-03-15 16:07:11 -0700511
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700512 self._post_start_hook(orig_params)
513
514 logging.info("AP configured.")
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700515 self.hostapd['configured'] = True
Sam Leffler6969d1d2010-03-15 16:07:11 -0700516
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700517
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700518 @staticmethod
519 def ip_addr(netblock, idx):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700520 """Simple IPv4 calculator.
521
522 Takes host address in "IP/bits" notation and returns netmask, broadcast
523 address as well as integer offsets into the address range.
524
525 @param netblock string host address in "IP/bits" notation.
526 @param idx string describing what to return.
527 @return string containing something you hopefully requested.
528
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700529 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700530 addr_str,bits = netblock.split('/')
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700531 addr = map(int, addr_str.split('.'))
532 mask_bits = (-1 << (32-int(bits))) & 0xffffffff
533 mask = [(mask_bits >> s) & 0xff for s in range(24, -1, -8)]
Paul Stewart5977da92011-06-01 19:14:08 -0700534 if idx == 'local':
535 return addr_str
536 elif idx == 'netmask':
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700537 return '.'.join(map(str, mask))
538 elif idx == 'broadcast':
539 offset = [m ^ 0xff for m in mask]
540 else:
541 offset = [(idx >> s) & 0xff for s in range(24, -1, -8)]
542 return '.'.join(map(str, [(a & m) + o
543 for a, m, o in zip(addr, mask, offset)]))
544
545
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700546 def ibss_configure(self, config):
547 """Configure a station based AP in IBSS mode.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700548
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700549 Extract relevant configuration objects from |config| despite not
550 actually being a hostap managed endpoint.
551
552 @param config HostapConfig object.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700553
554 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700555 if self.station['configured'] or self.hostapd['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700556 self.deconfig()
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700557 interface = self._get_wlanif(config.frequency, self.phytype,
558 config.hw_mode)
Christopher Wiley3166e432013-08-06 09:53:12 -0700559 self.station['conf']['ssid'] = (config.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700560 self._build_ssid(config.ssid_suffix))
Paul Stewartc2b3de82011-03-03 14:45:31 -0800561 # Connect the station
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700562 self.router.run('%s link set %s up' % (self.cmd_ip, interface))
Christopher Wiley3166e432013-08-06 09:53:12 -0700563 self.router.run('%s dev %s ibss join %s %d' % (
564 self.cmd_iw, interface, self.station['conf']['ssid'],
565 config.frequency))
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700566 # Always start a local server.
567 self.start_local_server(interface)
568 # Remember that this interface is up.
Paul Stewartc2b3de82011-03-03 14:45:31 -0800569 self.station['configured'] = True
570 self.station['interface'] = interface
571
572
Paul Stewart2bd823b2012-11-21 15:03:37 -0800573 def local_server_address(self, index):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700574 """Get the local server address for an interface.
575
576 When we multiple local servers, we give them static IP addresses
Christopher Wileyb1ade0a2013-09-16 13:09:55 -0700577 like 192.168.*.254.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700578
579 @param index int describing which local server this is for.
580
581 """
Christopher Wileyb1ade0a2013-09-16 13:09:55 -0700582 return '%d.%d.%d.%d' % (self.SUBNET_PREFIX_OCTETS + (index, 254))
Paul Stewart2bd823b2012-11-21 15:03:37 -0800583
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700584
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700585 def start_local_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700586 """Start a local server on an interface.
587
588 @param interface string (e.g. wlan0)
589
590 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700591 logging.info("Starting up local server...")
592
593 if len(self.local_servers) >= 256:
594 raise error.TestFail('Exhausted available local servers')
595
Paul Stewart2bd823b2012-11-21 15:03:37 -0800596 netblock = '%s/24' % self.local_server_address(len(self.local_servers))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700597
598 params = {}
599 params['netblock'] = netblock
600 params['subnet'] = self.ip_addr(netblock, 0)
601 params['netmask'] = self.ip_addr(netblock, 'netmask')
602 params['dhcp_range'] = ' '.join(
603 (self.ip_addr(netblock, self.dhcp_low),
604 self.ip_addr(netblock, self.dhcp_high)))
mukesh agrawal05c455a2011-10-12 13:40:27 -0700605 params['interface'] = interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700606
607 params['ip_params'] = ("%s broadcast %s dev %s" %
608 (netblock,
609 self.ip_addr(netblock, 'broadcast'),
610 interface))
611 self.local_servers.append(params)
612
613 self.router.run("%s addr flush %s" %
614 (self.cmd_ip, interface))
615 self.router.run("%s addr add %s" %
616 (self.cmd_ip, params['ip_params']))
617 self.router.run("%s link set %s up" %
618 (self.cmd_ip, interface))
Paul Stewart548cf452012-11-27 17:46:23 -0800619 self.start_dhcp_server(interface)
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700620
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700621
Paul Stewart548cf452012-11-27 17:46:23 -0800622 def start_dhcp_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700623 """Start a dhcp server on an interface.
624
625 @param interface string (e.g. wlan0)
626
627 """
Paul Stewart326badb2012-12-18 14:18:54 -0800628 conf_file = self.dhcpd_conf % interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700629 dhcp_conf = '\n'.join(map(
630 lambda server_conf: \
631 "subnet %(subnet)s netmask %(netmask)s {\n" \
632 " range %(dhcp_range)s;\n" \
633 "}" % server_conf,
634 self.local_servers))
635 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
Paul Stewart326badb2012-12-18 14:18:54 -0800636 (conf_file,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700637 '\n'.join(('ddns-update-style none;', dhcp_conf))))
638 self.router.run("touch %s" % self.dhcpd_leases)
639
640 self.router.run("pkill dhcpd >/dev/null 2>&1", ignore_status=True)
641 self.router.run("%s -q -cf %s -lf %s" %
Paul Stewart326badb2012-12-18 14:18:54 -0800642 (self.cmd_dhcpd, conf_file, self.dhcpd_leases))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700643
644
Paul Stewart326badb2012-12-18 14:18:54 -0800645 def stop_dhcp_server(self, instance=None):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700646 """Stop a dhcp server on the router.
647
648 @param instance string instance to kill.
649
650 """
Paul Stewart326badb2012-12-18 14:18:54 -0800651 self._kill_process_instance('dhcpd', instance, 0)
652
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700653
Paul Stewart548cf452012-11-27 17:46:23 -0800654 def stop_dhcp_servers(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700655 """Stop all dhcp servers on the router."""
Paul Stewart326badb2012-12-18 14:18:54 -0800656 self.stop_dhcp_server(None)
Paul Stewart548cf452012-11-27 17:46:23 -0800657
658
Paul Stewartc2b3de82011-03-03 14:45:31 -0800659 def config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700660 """Configure an AP based on site_wifitest parameters.
661
662 @param params dict of site_wifitest parameters.
663
664 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800665 if self.apmode:
666 self.hostap_config(params)
667 else:
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700668 config = hostap_config.HostapConfig(
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700669 frequency=int(params.get('channel', None)))
670 self.ibss_configure(config)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800671
672
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700673 def get_wifi_ip(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700674 """Return IP address on the WiFi subnet of a local server on the router.
675
676 If no local servers are configured (e.g. for an RSPro), a TestFail will
677 be raised.
678
679 @param ap_num int which local server to get an address from.
680
681 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700682 if self.local_servers:
683 return self.ip_addr(self.local_servers[ap_num]['netblock'],
684 'local')
685 else:
686 raise error.TestFail("No IP address assigned")
Paul Stewart5977da92011-06-01 19:14:08 -0700687
688
Paul Stewart17350be2012-12-14 13:34:54 -0800689 def get_hostapd_mac(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700690 """Return the MAC address of an AP in the test.
691
692 @param ap_num int index of local server to read the MAC address from.
693 @return string MAC address like 00:11:22:33:44:55.
694
695 """
Paul Stewart17350be2012-12-14 13:34:54 -0800696 instance = self.hostapd_instances[ap_num]
697 interface = instance['interface']
698 result = self.router.run('%s addr show %s' % (self.cmd_ip, interface))
699 # Example response:
700 # 1: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 UP qlen 1000
701 # link/ether 99:88:77:66:55:44 brd ff:ff:ff:ff:ff:ff
702 # inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
703 # inet6 fe80::6a7f:74ff:fe66:5544/64 scope link
704 # we want the MAC address after the "link/ether" above.
705 parts = result.stdout.split(' ')
706 return parts[parts.index('link/ether') + 1]
707
708
Christopher Wileyd89b5282013-04-10 15:21:26 -0700709 def deconfig(self, params={}):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700710 """De-configure the AP (will also bring wlan down).
Sam Leffler6969d1d2010-03-15 16:07:11 -0700711
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700712 @param params dict of parameters from site_wifitest.
713
714 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800715 if not self.hostapd['configured'] and not self.station['configured']:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700716 return
Sam Leffler6969d1d2010-03-15 16:07:11 -0700717
Paul Stewartc2b3de82011-03-03 14:45:31 -0800718 if self.hostapd['configured']:
Paul Stewart326badb2012-12-18 14:18:54 -0800719 local_servers = []
Paul Stewart21737812012-12-06 11:03:32 -0800720 if 'instance' in params:
721 instances = [ self.hostapd_instances.pop(params['instance']) ]
Paul Stewart326badb2012-12-18 14:18:54 -0800722 for server in self.local_servers:
723 if server['interface'] == instances[0]['interface']:
724 local_servers = [server]
725 self.local_servers.remove(server)
726 break
Paul Stewart21737812012-12-06 11:03:32 -0800727 else:
728 instances = self.hostapd_instances
729 self.hostapd_instances = []
Paul Stewart326badb2012-12-18 14:18:54 -0800730 local_servers = self.local_servers
731 self.local_servers = []
Paul Stewart64cc4292011-06-01 10:59:36 -0700732
Paul Stewart21737812012-12-06 11:03:32 -0800733 for instance in instances:
734 if 'silent' in params:
735 # Deconfigure without notifying DUT. Remove the interface
736 # hostapd uses to send beacon and DEAUTH packets.
737 self._remove_interface(instance['interface'], True)
738
Paul Stewart326badb2012-12-18 14:18:54 -0800739 self.kill_hostapd_instance(instance['conf_file'])
Paul Stewart548cf452012-11-27 17:46:23 -0800740 self.router.get_file(instance['log_file'],
741 'debug/hostapd_router_%d_%s.log' %
742 (self.hostapd['log_count'],
743 instance['interface']))
744 self._release_wlanif(instance['interface'])
745# self.router.run("rm -f %(log_file)s %(conf_file)s" % instance)
Paul Stewartf854d2e2011-05-04 13:19:18 -0700746 self.hostapd['log_count'] += 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800747 if self.station['configured']:
Christopher Wiley05262d62013-04-17 17:53:59 -0700748 local_servers = self.local_servers
749 self.local_servers = []
Paul Stewartc2b3de82011-03-03 14:45:31 -0800750 if self.station['type'] == 'ibss':
751 self.router.run("%s dev %s ibss leave" %
752 (self.cmd_iw, self.station['interface']))
753 else:
754 self.router.run("%s dev %s disconnect" %
755 (self.cmd_iw, self.station['interface']))
756 self.router.run("%s link set %s down" % (self.cmd_ip,
757 self.station['interface']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700758
Paul Stewart326badb2012-12-18 14:18:54 -0800759 for server in local_servers:
760 self.stop_dhcp_server(server['interface'])
761 self.router.run("%s addr del %s" %
762 (self.cmd_ip, server['ip_params']),
763 ignore_status=True)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700764
765 self.hostapd['configured'] = False
Paul Stewartc2b3de82011-03-03 14:45:31 -0800766 self.station['configured'] = False
Paul Stewart7cb1f062010-06-10 15:46:20 -0700767
768
Paul Stewart17350be2012-12-14 13:34:54 -0800769 def verify_pmksa_auth(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700770 """Verify that the PMKSA auth was cached on a hostapd instance.
771
772 @param params dict with optional key 'instance' (defaults to 0).
773
774 """
Paul Stewart17350be2012-12-14 13:34:54 -0800775 instance_num = params.get('instance', 0)
776 instance = self.hostapd_instances[instance_num]
777 pmksa_match = 'PMK from PMKSA cache - skip IEEE 802.1X.EAP'
778 self.router.run('grep -q "%s" %s' % (pmksa_match, instance['log_file']))
779
780
Paul Stewart7cb1f062010-06-10 15:46:20 -0700781 def get_ssid(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700782 """@return string ssid for the network stemming from this router."""
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700783 if self.hostapd['configured']:
784 return self.hostapd['conf']['ssid']
785
Christopher Wiley3166e432013-08-06 09:53:12 -0700786 if not 'ssid' in self.station['conf']:
787 raise error.TestFail('Requested ssid of an unconfigured AP.')
788
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700789 return self.station['conf']['ssid']
Paul Stewart98022e22010-10-22 10:33:14 -0700790
791
792 def set_txpower(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700793 """Set the transmission power for an interface.
794
795 Assumes that we want to refer to the first hostapd instance unless
796 'interface' is defined in params. Sets the transmission power to
797 'auto' if 'power' is not defined in params.
798
799 @param params dict of parameters as described above.
800
801 """
Paul Stewart548cf452012-11-27 17:46:23 -0800802 interface = params.get('interface',
803 self.hostapd_instances[0]['interface'])
804 power = params.get('power', 'auto')
Paul Stewart98022e22010-10-22 10:33:14 -0700805 self.router.run("%s dev %s set txpower %s" %
Paul Stewart548cf452012-11-27 17:46:23 -0800806 (self.cmd_iw, interface, power))
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700807
808
809 def deauth(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700810 """Deauthenticates a client described in params.
811
812 @param params dict containing a key 'client'.
813
814 """
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700815 self.router.run('%s -p%s deauthenticate %s' %
816 (self.cmd_hostapd_cli,
817 self.hostapd['conf']['ctrl_interface'],
818 params['client']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700819
820
Paul Stewart51b0f382013-06-12 09:03:02 -0700821 def send_management_frame(self, frame_type, instance=0):
822 """Injects a management frame into an active hostapd session.
823
824 @param frame_type string the type of frame to send.
825 @param instance int indicating which hostapd instance to inject into.
826
827 """
828 hostap_interface = self.hostapd_instances[instance]['interface']
829 interface = self._get_wlanif(0, 'monitor', same_phy_as=hostap_interface)
830 self.router.run("%s link set %s up" % (self.cmd_ip, interface))
831 self.router.run('%s %s %s' %
832 (self.cmd_send_management_frame, interface, frame_type))
833 self._release_wlanif(interface)
834
835
Paul Stewart25536942013-08-15 17:33:42 -0700836 def detect_client_deauth(self, client_mac, instance=0):
837 """Detects whether hostapd has logged a deauthentication from
838 |client_mac|.
839
840 @param client_mac string the MAC address of the client to detect.
841 @param instance int indicating which hostapd instance to query.
842
843 """
844 interface = self.hostapd_instances[instance]['interface']
845 deauth_msg = "%s: deauthentication: STA=%s" % (interface, client_mac)
846 log_file = self.hostapd_instances[instance]['log_file']
847 result = self.router.run("grep -qi '%s' %s" % (deauth_msg, log_file),
848 ignore_status=True)
849 return result.exit_status == 0
850
851
Paul Stewart4ae471e2013-09-04 15:42:35 -0700852 def detect_client_coexistence_report(self, client_mac, instance=0):
853 """Detects whether hostapd has logged an action frame from
854 |client_mac| indicating information about 20/40MHz BSS coexistence.
855
856 @param client_mac string the MAC address of the client to detect.
857 @param instance int indicating which hostapd instance to query.
858
859 """
860 coex_msg = ('nl80211: MLME event frame - hexdump(len=.*): '
861 '.. .. .. .. .. .. .. .. .. .. %s '
862 '.. .. .. .. .. .. .. .. 04 00.*48 01 ..' %
863 ' '.join(client_mac.split(':')))
864 log_file = self.hostapd_instances[instance]['log_file']
865 result = self.router.run("grep -qi '%s' %s" % (coex_msg, log_file),
866 ignore_status=True)
867 return result.exit_status == 0
868
869
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700870 def _pre_config_hook(self, config):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700871 """Hook for subclasses.
872
873 Run after gathering configuration parameters,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700874 but before writing parameters to config file.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700875
876 @param config dict containing hostapd config parameters.
877
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700878 """
879 pass
880
881
882 def _pre_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700883 """Hook for subclasses.
884
885 Run after generating hostapd config file, but before starting hostapd.
886
887 @param params dict parameters from site_wifitest.
888
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700889 """
890 pass
891
892
893 def _post_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700894 """Hook for subclasses run after starting hostapd.
895
896 @param params dict parameters from site_wifitest.
897
898 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700899 pass