blob: cd30f40b426c7cc539d7b00f1b5b4cb22badb496 [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 Wiley14796b32013-04-03 14:53:33 -07009
Wade Guthriee4074dd2013-10-30 11:00:48 -070010from autotest_lib.client.common_lib import base_utils
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'))
Christopher Wiley7337ff62013-10-03 17:21:46 -070073 self.cmd_hostapd_cli = wifi_test_utils.must_be_installed(
74 host, params.get('cmd_hostapd_cli', '/usr/sbin/hostapd_cli'))
Christopher Wileyf99e6cc2013-04-19 10:12:43 -070075 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
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700118 self.iw_runner.set_regulatory_domain('US')
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
Christopher Wiley7337ff62013-10-03 17:21:46 -0700190 def get_hostapd_start_command(self, log_file, pid_file, conf_file):
191 return '%s -dd -t -P %s %s &> %s &' % (
192 self.cmd_hostapd, pid_file, conf_file, log_file)
193
194
Paul Stewart548cf452012-11-27 17:46:23 -0800195 def start_hostapd(self, conf, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700196 """Start a hostapd instance described by conf.
197
198 @param conf dict of hostapd configuration parameters.
199 @param params dict of site_wifitest parameters.
200
201 """
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700202 logging.info('Starting hostapd with parameters: %r', conf)
Paul Stewart548cf452012-11-27 17:46:23 -0800203 # Figure out the correct interface.
Paul Stewart326badb2012-12-18 14:18:54 -0800204 interface = self._get_wlanif(self.hostapd['frequency'],
205 self.phytype,
206 mode=conf.get('hw_mode', 'b'))
207
208 conf_file = self.hostapd['config_file'] % interface
209 log_file = self.hostapd['log_file'] % interface
Christopher Wiley1defc242013-09-18 10:28:37 -0700210 pid_file = self.hostapd['pid_file'] % interface
Paul Stewart326badb2012-12-18 14:18:54 -0800211 conf['interface'] = interface
Paul Stewart548cf452012-11-27 17:46:23 -0800212
213 # Generate hostapd.conf.
214 self._pre_config_hook(conf)
215 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
216 (conf_file, '\n'.join(
217 "%s=%s" % kv for kv in conf.iteritems())))
218
219 # Run hostapd.
220 logging.info("Starting hostapd...")
Christopher Wiley1defc242013-09-18 10:28:37 -0700221 self.router.run('rm %s' % log_file, ignore_status=True)
222 self.router.run('rm %s' % pid_file, ignore_status=True)
Paul Stewart548cf452012-11-27 17:46:23 -0800223 self._pre_start_hook(params)
Christopher Wiley7337ff62013-10-03 17:21:46 -0700224 start_command = self.get_hostapd_start_command(
225 log_file, pid_file, conf_file)
226 self.router.run(start_command)
Paul Stewart548cf452012-11-27 17:46:23 -0800227 self.hostapd_instances.append({
228 'conf_file': conf_file,
229 'log_file': log_file,
Christopher Wiley1defc242013-09-18 10:28:37 -0700230 'interface': interface,
231 'pid_file': pid_file
Paul Stewart548cf452012-11-27 17:46:23 -0800232 })
233
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700234
Paul Stewart326badb2012-12-18 14:18:54 -0800235 def _kill_process_instance(self, process, instance=None, wait=0):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700236 """Kill a process on the router.
237
Paul Stewart326badb2012-12-18 14:18:54 -0800238 Kills program named |process|, optionally only a specific
239 |instance|. If |wait| is specified, we makes sure |process| exits
240 before returning.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700241
242 @param process string name of process to kill.
243 @param instance string instance of process to kill.
244 @param wait int timeout in seconds to wait for.
245
Thieu Le7b23a542012-01-27 15:54:48 -0800246 """
Paul Stewart21737812012-12-06 11:03:32 -0800247 if instance:
Paul Stewart326badb2012-12-18 14:18:54 -0800248 search_arg = '-f "%s.*%s"' % (process, instance)
Paul Stewart21737812012-12-06 11:03:32 -0800249 else:
Paul Stewart326badb2012-12-18 14:18:54 -0800250 search_arg = process
Paul Stewart21737812012-12-06 11:03:32 -0800251
Paul Stewart326badb2012-12-18 14:18:54 -0800252 cmd = "pkill %s >/dev/null 2>&1" % search_arg
253
254 if wait:
255 cmd += (" && while pgrep %s &> /dev/null; do sleep 1; done" %
256 search_arg)
257 self.router.run(cmd, timeout=wait, ignore_status=True)
258 else:
259 self.router.run(cmd, ignore_status=True)
260
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700261
Paul Stewart326badb2012-12-18 14:18:54 -0800262 def kill_hostapd_instance(self, instance):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700263 """Kills a hostapd instance.
264
265 @param instance string instance to kill.
266
267 """
Paul Stewart326badb2012-12-18 14:18:54 -0800268 self._kill_process_instance('hostapd', instance, 30)
Thieu Le7b23a542012-01-27 15:54:48 -0800269
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700270
Paul Stewart21737812012-12-06 11:03:32 -0800271 def kill_hostapd(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700272 """Kill all hostapd instances."""
Paul Stewart21737812012-12-06 11:03:32 -0800273 self.kill_hostapd_instance(None)
274
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700275
276 def __get_default_hostap_config(self):
277 """@return dict of default options for hostapd."""
278 conf = self.hostapd['conf']
279 # default RTS and frag threshold to ``off''
280 conf['rts_threshold'] = '2347'
281 conf['fragm_threshold'] = '2346'
282 conf['driver'] = self.hostapd['driver']
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700283 conf['ssid'] = self._build_ssid('')
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700284 return conf
285
286
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700287 def _build_ssid(self, suffix):
Christopher Wiley3166e432013-08-06 09:53:12 -0700288 unique_salt = ''.join([random.choice(self.SUFFIX_LETTERS)
289 for x in range(5)])
290 return (self.ssid_prefix + unique_salt + suffix)[-32:]
291
292
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700293 def hostap_configure(self, configuration, multi_interface=None):
294 """Build up a hostapd configuration file and start hostapd.
295
296 Also setup a local server if this router supports them.
297
298 @param configuration HosetapConfig object.
299 @param multi_interface bool True iff multiple interfaces allowed.
300
301 """
302 if multi_interface is None and (self.hostapd['configured'] or
303 self.station['configured']):
304 self.deconfig()
305 # Start with the default hostapd config parameters.
306 conf = self.__get_default_hostap_config()
Christopher Wiley3166e432013-08-06 09:53:12 -0700307 conf['ssid'] = (configuration.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700308 self._build_ssid(configuration.ssid_suffix))
Christopher Wiley9b406202013-05-06 14:07:49 -0700309 if configuration.bssid:
310 conf['bssid'] = configuration.bssid
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700311 conf['channel'] = configuration.channel
312 self.hostapd['frequency'] = configuration.frequency
313 conf['hw_mode'] = configuration.hw_mode
314 if configuration.hide_ssid:
315 conf['ignore_broadcast_ssid'] = 1
316 if configuration.is_11n:
317 conf['ieee80211n'] = 1
Christopher Wiley32fbb7a2013-09-18 14:30:50 -0700318 conf['ht_capab'] = configuration.hostapd_ht_capabilities
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700319 if configuration.wmm_enabled:
320 conf['wmm_enabled'] = 1
321 if configuration.require_ht:
322 conf['require_ht'] = 1
Christopher Wiley9fa7c632013-05-01 11:58:06 -0700323 if configuration.beacon_interval:
324 conf['beacon_int'] = configuration.beacon_interval
Christopher Wileya51258e2013-05-03 13:05:06 -0700325 if configuration.dtim_period:
326 conf['dtim_period'] = configuration.dtim_period
Christopher Wileye1235b62013-05-03 15:09:34 -0700327 if configuration.frag_threshold:
328 conf['fragm_threshold'] = configuration.frag_threshold
Christopher Wileyebdc27d2013-06-28 14:35:41 -0700329 if configuration.pmf_support:
330 conf['ieee80211w'] = configuration.pmf_support
Paul Stewart4ae471e2013-09-04 15:42:35 -0700331 if configuration.obss_interval:
332 conf['obss_interval'] = configuration.obss_interval
Christopher Wileyb8921c72013-06-13 09:51:47 -0700333 conf.update(configuration.get_security_hostapd_conf())
Christopher Wileya89706d2013-06-12 13:20:58 -0700334
Wade Guthriefcaaf022013-09-06 11:12:22 -0700335 # TODO(wiley): Remove this multi_interface flag when the bridge router
336 # class is gone.
337 params = {'multi_interface': 1} if multi_interface else {}
338 self.start_hostapd(conf, params)
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700339 # Configure transmit power
340 tx_power_params = {'interface': conf['interface']}
341 # TODO(wiley) support for setting transmit power
342 self.set_txpower(tx_power_params)
343 if self.force_local_server:
344 self.start_local_server(conf['interface'])
Wade Guthriefcaaf022013-09-06 11:12:22 -0700345 self._post_start_hook(params)
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700346 logging.info('AP configured.')
347 self.hostapd['configured'] = True
348
349
Paul Stewartc2b3de82011-03-03 14:45:31 -0800350 def hostap_config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700351 """Configure the AP per test requirements.
Sam Leffler6969d1d2010-03-15 16:07:11 -0700352
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700353 @param params dict of site_wifitest parameters.
354
355 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700356 # keep parameter modifications local-only
357 orig_params = params
358 params = params.copy()
359
Paul Stewart45338d22010-10-21 10:57:02 -0700360 multi_interface = 'multi_interface' in params
361 if multi_interface:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700362 # remove non-hostapd config item from params
Paul Stewart45338d22010-10-21 10:57:02 -0700363 params.pop('multi_interface')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800364 elif self.hostapd['configured'] or self.station['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700365 self.deconfig()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700366
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700367 local_server = params.pop('local_server', False)
368
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700369 conf = self.__get_default_hostap_config()
Paul Stewartc2b3de82011-03-03 14:45:31 -0800370 tx_power_params = {}
371 htcaps = set()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700372
Paul Stewartc2b3de82011-03-03 14:45:31 -0800373 for k, v in params.iteritems():
374 if k == 'ssid':
375 conf['ssid'] = v
376 elif k == 'ssid_suffix':
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700377 conf['ssid'] = self._build_ssid(v)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800378 elif k == 'channel':
379 freq = int(v)
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700380 self.hostapd['frequency'] = freq
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700381
Paul Stewartc2b3de82011-03-03 14:45:31 -0800382 # 2.4GHz
383 if freq <= 2484:
384 # Make sure hw_mode is set
385 if conf.get('hw_mode') == 'a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700386 conf['hw_mode'] = 'g'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800387
388 # Freq = 5 * chan + 2407, except channel 14
389 if freq == 2484:
390 conf['channel'] = 14
391 else:
392 conf['channel'] = (freq - 2407) / 5
393 # 5GHz
Sam Leffler6969d1d2010-03-15 16:07:11 -0700394 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800395 # Make sure hw_mode is set
396 conf['hw_mode'] = 'a'
397 # Freq = 5 * chan + 4000
398 if freq < 5000:
399 conf['channel'] = (freq - 4000) / 5
400 # Freq = 5 * chan + 5000
401 else:
402 conf['channel'] = (freq - 5000) / 5
Sam Leffler6969d1d2010-03-15 16:07:11 -0700403
Paul Stewartc2b3de82011-03-03 14:45:31 -0800404 elif k == 'country':
405 conf['country_code'] = v
406 elif k == 'dotd':
407 conf['ieee80211d'] = 1
408 elif k == '-dotd':
409 conf['ieee80211d'] = 0
410 elif k == 'mode':
411 if v == '11a':
412 conf['hw_mode'] = 'a'
413 elif v == '11g':
414 conf['hw_mode'] = 'g'
415 elif v == '11b':
416 conf['hw_mode'] = 'b'
417 elif v == '11n':
418 conf['ieee80211n'] = 1
419 elif k == 'bintval':
420 conf['beacon_int'] = v
421 elif k == 'dtimperiod':
422 conf['dtim_period'] = v
423 elif k == 'rtsthreshold':
424 conf['rts_threshold'] = v
425 elif k == 'fragthreshold':
426 conf['fragm_threshold'] = v
427 elif k == 'shortpreamble':
428 conf['preamble'] = 1
429 elif k == 'authmode':
430 if v == "open":
431 conf['auth_algs'] = 1
432 elif v == "shared":
433 conf['auth_algs'] = 2
434 elif k == 'hidessid':
435 conf['ignore_broadcast_ssid'] = 1
436 elif k == 'wme':
437 conf['wmm_enabled'] = 1
438 elif k == '-wme':
439 conf['wmm_enabled'] = 0
440 elif k == 'deftxkey':
441 conf['wep_default_key'] = v
442 elif k == 'ht20':
443 htcaps.add('') # NB: ensure 802.11n setup below
444 conf['wmm_enabled'] = 1
445 elif k == 'ht40':
446 htcaps.add('[HT40-]')
447 htcaps.add('[HT40+]')
448 conf['wmm_enabled'] = 1
Paul Stewartc1df8d62011-04-07 14:28:15 -0700449 elif k in ('ht40+', 'ht40-'):
450 htcaps.add('[%s]' % k.upper())
451 conf['wmm_enabled'] = 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800452 elif k == 'shortgi':
453 htcaps.add('[SHORT-GI-20]')
454 htcaps.add('[SHORT-GI-40]')
455 elif k == 'pureg':
456 pass # TODO(sleffler) need hostapd support
457 elif k == 'puren':
458 pass # TODO(sleffler) need hostapd support
459 elif k == 'protmode':
460 pass # TODO(sleffler) need hostapd support
461 elif k == 'ht':
462 htcaps.add('') # NB: ensure 802.11n setup below
463 elif k == 'htprotmode':
464 pass # TODO(sleffler) need hostapd support
465 elif k == 'rifs':
466 pass # TODO(sleffler) need hostapd support
467 elif k == 'wepmode':
468 pass # NB: meaningless for hostapd; ignore
469 elif k == '-ampdu':
470 pass # TODO(sleffler) need hostapd support
471 elif k == 'txpower':
472 tx_power_params['power'] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700473 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800474 conf[k] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700475
Paul Stewartc2b3de82011-03-03 14:45:31 -0800476 # Aggregate ht_capab.
477 if htcaps:
478 conf['ieee80211n'] = 1
479 conf['ht_capab'] = ''.join(htcaps)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700480
Paul Stewart548cf452012-11-27 17:46:23 -0800481 self.start_hostapd(conf, orig_params)
Paul Stewart1ae854b2011-02-08 15:10:14 -0800482
Paul Stewartc2b3de82011-03-03 14:45:31 -0800483 # Configure transmit power
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700484 tx_power_params['interface'] = conf['interface']
Paul Stewartc2b3de82011-03-03 14:45:31 -0800485 self.set_txpower(tx_power_params)
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700486
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700487 if self.force_local_server or local_server is not False:
488 self.start_local_server(conf['interface'])
Sam Leffler6969d1d2010-03-15 16:07:11 -0700489
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700490 self._post_start_hook(orig_params)
491
492 logging.info("AP configured.")
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700493 self.hostapd['configured'] = True
Sam Leffler6969d1d2010-03-15 16:07:11 -0700494
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700495
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700496 @staticmethod
497 def ip_addr(netblock, idx):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700498 """Simple IPv4 calculator.
499
500 Takes host address in "IP/bits" notation and returns netmask, broadcast
501 address as well as integer offsets into the address range.
502
503 @param netblock string host address in "IP/bits" notation.
504 @param idx string describing what to return.
505 @return string containing something you hopefully requested.
506
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700507 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700508 addr_str,bits = netblock.split('/')
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700509 addr = map(int, addr_str.split('.'))
510 mask_bits = (-1 << (32-int(bits))) & 0xffffffff
511 mask = [(mask_bits >> s) & 0xff for s in range(24, -1, -8)]
Paul Stewart5977da92011-06-01 19:14:08 -0700512 if idx == 'local':
513 return addr_str
514 elif idx == 'netmask':
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700515 return '.'.join(map(str, mask))
516 elif idx == 'broadcast':
517 offset = [m ^ 0xff for m in mask]
518 else:
519 offset = [(idx >> s) & 0xff for s in range(24, -1, -8)]
520 return '.'.join(map(str, [(a & m) + o
521 for a, m, o in zip(addr, mask, offset)]))
522
523
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700524 def ibss_configure(self, config):
525 """Configure a station based AP in IBSS mode.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700526
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700527 Extract relevant configuration objects from |config| despite not
528 actually being a hostap managed endpoint.
529
530 @param config HostapConfig object.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700531
532 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700533 if self.station['configured'] or self.hostapd['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700534 self.deconfig()
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700535 interface = self._get_wlanif(config.frequency, self.phytype,
536 config.hw_mode)
Christopher Wiley3166e432013-08-06 09:53:12 -0700537 self.station['conf']['ssid'] = (config.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700538 self._build_ssid(config.ssid_suffix))
Paul Stewartc2b3de82011-03-03 14:45:31 -0800539 # Connect the station
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700540 self.router.run('%s link set %s up' % (self.cmd_ip, interface))
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700541 self.iw_runner.ibss_join(
542 interface, self.station['conf']['ssid'], config.frequency)
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700543 # Always start a local server.
544 self.start_local_server(interface)
545 # Remember that this interface is up.
Paul Stewartc2b3de82011-03-03 14:45:31 -0800546 self.station['configured'] = True
547 self.station['interface'] = interface
548
549
Paul Stewart2bd823b2012-11-21 15:03:37 -0800550 def local_server_address(self, index):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700551 """Get the local server address for an interface.
552
553 When we multiple local servers, we give them static IP addresses
Christopher Wileyb1ade0a2013-09-16 13:09:55 -0700554 like 192.168.*.254.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700555
556 @param index int describing which local server this is for.
557
558 """
Christopher Wileyb1ade0a2013-09-16 13:09:55 -0700559 return '%d.%d.%d.%d' % (self.SUBNET_PREFIX_OCTETS + (index, 254))
Paul Stewart2bd823b2012-11-21 15:03:37 -0800560
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700561
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700562 def start_local_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700563 """Start a local server on an interface.
564
565 @param interface string (e.g. wlan0)
566
567 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700568 logging.info("Starting up local server...")
569
570 if len(self.local_servers) >= 256:
571 raise error.TestFail('Exhausted available local servers')
572
Paul Stewart2bd823b2012-11-21 15:03:37 -0800573 netblock = '%s/24' % self.local_server_address(len(self.local_servers))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700574
575 params = {}
576 params['netblock'] = netblock
577 params['subnet'] = self.ip_addr(netblock, 0)
578 params['netmask'] = self.ip_addr(netblock, 'netmask')
579 params['dhcp_range'] = ' '.join(
580 (self.ip_addr(netblock, self.dhcp_low),
581 self.ip_addr(netblock, self.dhcp_high)))
mukesh agrawal05c455a2011-10-12 13:40:27 -0700582 params['interface'] = interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700583
584 params['ip_params'] = ("%s broadcast %s dev %s" %
585 (netblock,
586 self.ip_addr(netblock, 'broadcast'),
587 interface))
588 self.local_servers.append(params)
589
590 self.router.run("%s addr flush %s" %
591 (self.cmd_ip, interface))
592 self.router.run("%s addr add %s" %
593 (self.cmd_ip, params['ip_params']))
594 self.router.run("%s link set %s up" %
595 (self.cmd_ip, interface))
Paul Stewart548cf452012-11-27 17:46:23 -0800596 self.start_dhcp_server(interface)
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700597
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700598
Paul Stewart548cf452012-11-27 17:46:23 -0800599 def start_dhcp_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700600 """Start a dhcp server on an interface.
601
602 @param interface string (e.g. wlan0)
603
604 """
Paul Stewart326badb2012-12-18 14:18:54 -0800605 conf_file = self.dhcpd_conf % interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700606 dhcp_conf = '\n'.join(map(
607 lambda server_conf: \
608 "subnet %(subnet)s netmask %(netmask)s {\n" \
609 " range %(dhcp_range)s;\n" \
610 "}" % server_conf,
611 self.local_servers))
612 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
Paul Stewart326badb2012-12-18 14:18:54 -0800613 (conf_file,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700614 '\n'.join(('ddns-update-style none;', dhcp_conf))))
615 self.router.run("touch %s" % self.dhcpd_leases)
616
617 self.router.run("pkill dhcpd >/dev/null 2>&1", ignore_status=True)
618 self.router.run("%s -q -cf %s -lf %s" %
Paul Stewart326badb2012-12-18 14:18:54 -0800619 (self.cmd_dhcpd, conf_file, self.dhcpd_leases))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700620
621
Paul Stewart326badb2012-12-18 14:18:54 -0800622 def stop_dhcp_server(self, instance=None):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700623 """Stop a dhcp server on the router.
624
625 @param instance string instance to kill.
626
627 """
Paul Stewart326badb2012-12-18 14:18:54 -0800628 self._kill_process_instance('dhcpd', instance, 0)
629
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700630
Paul Stewart548cf452012-11-27 17:46:23 -0800631 def stop_dhcp_servers(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700632 """Stop all dhcp servers on the router."""
Paul Stewart326badb2012-12-18 14:18:54 -0800633 self.stop_dhcp_server(None)
Paul Stewart548cf452012-11-27 17:46:23 -0800634
635
Paul Stewartc2b3de82011-03-03 14:45:31 -0800636 def config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700637 """Configure an AP based on site_wifitest parameters.
638
639 @param params dict of site_wifitest parameters.
640
641 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800642 if self.apmode:
643 self.hostap_config(params)
644 else:
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700645 config = hostap_config.HostapConfig(
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700646 frequency=int(params.get('channel', None)))
647 self.ibss_configure(config)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800648
649
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700650 def get_wifi_ip(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700651 """Return IP address on the WiFi subnet of a local server on the router.
652
653 If no local servers are configured (e.g. for an RSPro), a TestFail will
654 be raised.
655
656 @param ap_num int which local server to get an address from.
657
658 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700659 if self.local_servers:
660 return self.ip_addr(self.local_servers[ap_num]['netblock'],
661 'local')
662 else:
663 raise error.TestFail("No IP address assigned")
Paul Stewart5977da92011-06-01 19:14:08 -0700664
665
Paul Stewart17350be2012-12-14 13:34:54 -0800666 def get_hostapd_mac(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700667 """Return the MAC address of an AP in the test.
668
669 @param ap_num int index of local server to read the MAC address from.
670 @return string MAC address like 00:11:22:33:44:55.
671
672 """
Paul Stewart17350be2012-12-14 13:34:54 -0800673 instance = self.hostapd_instances[ap_num]
674 interface = instance['interface']
675 result = self.router.run('%s addr show %s' % (self.cmd_ip, interface))
676 # Example response:
677 # 1: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 UP qlen 1000
678 # link/ether 99:88:77:66:55:44 brd ff:ff:ff:ff:ff:ff
679 # inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
680 # inet6 fe80::6a7f:74ff:fe66:5544/64 scope link
681 # we want the MAC address after the "link/ether" above.
682 parts = result.stdout.split(' ')
683 return parts[parts.index('link/ether') + 1]
684
685
Christopher Wileyd89b5282013-04-10 15:21:26 -0700686 def deconfig(self, params={}):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700687 """De-configure the AP (will also bring wlan down).
Sam Leffler6969d1d2010-03-15 16:07:11 -0700688
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700689 @param params dict of parameters from site_wifitest.
690
691 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800692 if not self.hostapd['configured'] and not self.station['configured']:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700693 return
Sam Leffler6969d1d2010-03-15 16:07:11 -0700694
Paul Stewartc2b3de82011-03-03 14:45:31 -0800695 if self.hostapd['configured']:
Paul Stewart326badb2012-12-18 14:18:54 -0800696 local_servers = []
Paul Stewart21737812012-12-06 11:03:32 -0800697 if 'instance' in params:
698 instances = [ self.hostapd_instances.pop(params['instance']) ]
Paul Stewart326badb2012-12-18 14:18:54 -0800699 for server in self.local_servers:
700 if server['interface'] == instances[0]['interface']:
701 local_servers = [server]
702 self.local_servers.remove(server)
703 break
Paul Stewart21737812012-12-06 11:03:32 -0800704 else:
705 instances = self.hostapd_instances
706 self.hostapd_instances = []
Paul Stewart326badb2012-12-18 14:18:54 -0800707 local_servers = self.local_servers
708 self.local_servers = []
Paul Stewart64cc4292011-06-01 10:59:36 -0700709
Paul Stewart21737812012-12-06 11:03:32 -0800710 for instance in instances:
711 if 'silent' in params:
712 # Deconfigure without notifying DUT. Remove the interface
713 # hostapd uses to send beacon and DEAUTH packets.
714 self._remove_interface(instance['interface'], True)
715
Paul Stewart326badb2012-12-18 14:18:54 -0800716 self.kill_hostapd_instance(instance['conf_file'])
Christopher Wiley7337ff62013-10-03 17:21:46 -0700717 if wifi_test_utils.is_installed(self.host,
718 instance['log_file']):
719 self.router.get_file(instance['log_file'],
720 'debug/hostapd_router_%d_%s.log' %
721 (self.hostapd['log_count'],
722 instance['interface']))
723 else:
724 logging.error('Did not collect hostapd log file because '
725 'it was missing.')
Paul Stewart548cf452012-11-27 17:46:23 -0800726 self._release_wlanif(instance['interface'])
727# self.router.run("rm -f %(log_file)s %(conf_file)s" % instance)
Paul Stewartf854d2e2011-05-04 13:19:18 -0700728 self.hostapd['log_count'] += 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800729 if self.station['configured']:
Christopher Wiley05262d62013-04-17 17:53:59 -0700730 local_servers = self.local_servers
731 self.local_servers = []
Paul Stewartc2b3de82011-03-03 14:45:31 -0800732 if self.station['type'] == 'ibss':
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700733 self.iw_runner.ibss_leave(self.station['interface'])
Paul Stewartc2b3de82011-03-03 14:45:31 -0800734 else:
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700735 self.iw_runner.disconnect_station(self.station['interface'])
Paul Stewartc2b3de82011-03-03 14:45:31 -0800736 self.router.run("%s link set %s down" % (self.cmd_ip,
737 self.station['interface']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700738
Paul Stewart326badb2012-12-18 14:18:54 -0800739 for server in local_servers:
740 self.stop_dhcp_server(server['interface'])
741 self.router.run("%s addr del %s" %
742 (self.cmd_ip, server['ip_params']),
743 ignore_status=True)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700744
745 self.hostapd['configured'] = False
Paul Stewartc2b3de82011-03-03 14:45:31 -0800746 self.station['configured'] = False
Paul Stewart7cb1f062010-06-10 15:46:20 -0700747
748
Paul Stewart17350be2012-12-14 13:34:54 -0800749 def verify_pmksa_auth(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700750 """Verify that the PMKSA auth was cached on a hostapd instance.
751
752 @param params dict with optional key 'instance' (defaults to 0).
753
754 """
Paul Stewart17350be2012-12-14 13:34:54 -0800755 instance_num = params.get('instance', 0)
756 instance = self.hostapd_instances[instance_num]
757 pmksa_match = 'PMK from PMKSA cache - skip IEEE 802.1X.EAP'
758 self.router.run('grep -q "%s" %s' % (pmksa_match, instance['log_file']))
759
760
Paul Stewart7cb1f062010-06-10 15:46:20 -0700761 def get_ssid(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700762 """@return string ssid for the network stemming from this router."""
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700763 if self.hostapd['configured']:
764 return self.hostapd['conf']['ssid']
765
Christopher Wiley3166e432013-08-06 09:53:12 -0700766 if not 'ssid' in self.station['conf']:
767 raise error.TestFail('Requested ssid of an unconfigured AP.')
768
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700769 return self.station['conf']['ssid']
Paul Stewart98022e22010-10-22 10:33:14 -0700770
771
772 def set_txpower(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700773 """Set the transmission power for an interface.
774
775 Assumes that we want to refer to the first hostapd instance unless
776 'interface' is defined in params. Sets the transmission power to
777 'auto' if 'power' is not defined in params.
778
779 @param params dict of parameters as described above.
780
781 """
Paul Stewart548cf452012-11-27 17:46:23 -0800782 interface = params.get('interface',
783 self.hostapd_instances[0]['interface'])
784 power = params.get('power', 'auto')
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700785 self.iw_runner.set_tx_power(interface, power)
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700786
787
Wade Guthriee4074dd2013-10-30 11:00:48 -0700788 def deauth_client(self, client_mac):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700789 """Deauthenticates a client described in params.
790
Wade Guthriee4074dd2013-10-30 11:00:48 -0700791 @param client_mac string containing the mac address of the client to be
792 deauthenticated.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700793
794 """
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700795 self.router.run('%s -p%s deauthenticate %s' %
796 (self.cmd_hostapd_cli,
797 self.hostapd['conf']['ctrl_interface'],
Wade Guthriee4074dd2013-10-30 11:00:48 -0700798 client_mac))
799
800
801 @base_utils.deprecated
802 def deauth(self, params):
803 """Deauthenticates a client described in params.
804
805 Deprecated: Call 'deauth_client', instead.
806
807 @param params dict containing a key 'client'.
808
809 """
810 self.deauth_client(params['client'])
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700811
812
Paul Stewart51b0f382013-06-12 09:03:02 -0700813 def send_management_frame(self, frame_type, instance=0):
814 """Injects a management frame into an active hostapd session.
815
816 @param frame_type string the type of frame to send.
817 @param instance int indicating which hostapd instance to inject into.
818
819 """
820 hostap_interface = self.hostapd_instances[instance]['interface']
821 interface = self._get_wlanif(0, 'monitor', same_phy_as=hostap_interface)
822 self.router.run("%s link set %s up" % (self.cmd_ip, interface))
823 self.router.run('%s %s %s' %
824 (self.cmd_send_management_frame, interface, frame_type))
825 self._release_wlanif(interface)
826
827
Paul Stewart25536942013-08-15 17:33:42 -0700828 def detect_client_deauth(self, client_mac, instance=0):
829 """Detects whether hostapd has logged a deauthentication from
830 |client_mac|.
831
832 @param client_mac string the MAC address of the client to detect.
833 @param instance int indicating which hostapd instance to query.
834
835 """
836 interface = self.hostapd_instances[instance]['interface']
837 deauth_msg = "%s: deauthentication: STA=%s" % (interface, client_mac)
838 log_file = self.hostapd_instances[instance]['log_file']
839 result = self.router.run("grep -qi '%s' %s" % (deauth_msg, log_file),
840 ignore_status=True)
841 return result.exit_status == 0
842
843
Paul Stewart4ae471e2013-09-04 15:42:35 -0700844 def detect_client_coexistence_report(self, client_mac, instance=0):
845 """Detects whether hostapd has logged an action frame from
846 |client_mac| indicating information about 20/40MHz BSS coexistence.
847
848 @param client_mac string the MAC address of the client to detect.
849 @param instance int indicating which hostapd instance to query.
850
851 """
852 coex_msg = ('nl80211: MLME event frame - hexdump(len=.*): '
853 '.. .. .. .. .. .. .. .. .. .. %s '
854 '.. .. .. .. .. .. .. .. 04 00.*48 01 ..' %
855 ' '.join(client_mac.split(':')))
856 log_file = self.hostapd_instances[instance]['log_file']
857 result = self.router.run("grep -qi '%s' %s" % (coex_msg, log_file),
858 ignore_status=True)
859 return result.exit_status == 0
860
861
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700862 def _pre_config_hook(self, config):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700863 """Hook for subclasses.
864
865 Run after gathering configuration parameters,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700866 but before writing parameters to config file.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700867
868 @param config dict containing hostapd config parameters.
869
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700870 """
871 pass
872
873
874 def _pre_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700875 """Hook for subclasses.
876
877 Run after generating hostapd config file, but before starting hostapd.
878
879 @param params dict parameters from site_wifitest.
880
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700881 """
882 pass
883
884
885 def _post_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700886 """Hook for subclasses run after starting hostapd.
887
888 @param params dict parameters from site_wifitest.
889
890 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700891 pass