blob: a4d9b8a7fecd6cc06fe437d46c576cec7fd578f8 [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({
Christopher Wiley3099be72013-11-06 16:49:02 -0800228 'ssid': conf['ssid'],
Paul Stewart548cf452012-11-27 17:46:23 -0800229 'conf_file': conf_file,
230 'log_file': log_file,
Christopher Wiley1defc242013-09-18 10:28:37 -0700231 'interface': interface,
232 'pid_file': pid_file
Paul Stewart548cf452012-11-27 17:46:23 -0800233 })
234
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700235
Paul Stewart326badb2012-12-18 14:18:54 -0800236 def _kill_process_instance(self, process, instance=None, wait=0):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700237 """Kill a process on the router.
238
Paul Stewart326badb2012-12-18 14:18:54 -0800239 Kills program named |process|, optionally only a specific
240 |instance|. If |wait| is specified, we makes sure |process| exits
241 before returning.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700242
243 @param process string name of process to kill.
244 @param instance string instance of process to kill.
245 @param wait int timeout in seconds to wait for.
246
Thieu Le7b23a542012-01-27 15:54:48 -0800247 """
Paul Stewart21737812012-12-06 11:03:32 -0800248 if instance:
Paul Stewart326badb2012-12-18 14:18:54 -0800249 search_arg = '-f "%s.*%s"' % (process, instance)
Paul Stewart21737812012-12-06 11:03:32 -0800250 else:
Paul Stewart326badb2012-12-18 14:18:54 -0800251 search_arg = process
Paul Stewart21737812012-12-06 11:03:32 -0800252
Paul Stewart326badb2012-12-18 14:18:54 -0800253 cmd = "pkill %s >/dev/null 2>&1" % search_arg
254
255 if wait:
256 cmd += (" && while pgrep %s &> /dev/null; do sleep 1; done" %
257 search_arg)
258 self.router.run(cmd, timeout=wait, ignore_status=True)
259 else:
260 self.router.run(cmd, ignore_status=True)
261
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700262
Paul Stewart326badb2012-12-18 14:18:54 -0800263 def kill_hostapd_instance(self, instance):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700264 """Kills a hostapd instance.
265
266 @param instance string instance to kill.
267
268 """
Paul Stewart326badb2012-12-18 14:18:54 -0800269 self._kill_process_instance('hostapd', instance, 30)
Thieu Le7b23a542012-01-27 15:54:48 -0800270
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700271
Paul Stewart21737812012-12-06 11:03:32 -0800272 def kill_hostapd(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700273 """Kill all hostapd instances."""
Paul Stewart21737812012-12-06 11:03:32 -0800274 self.kill_hostapd_instance(None)
275
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700276
277 def __get_default_hostap_config(self):
278 """@return dict of default options for hostapd."""
279 conf = self.hostapd['conf']
280 # default RTS and frag threshold to ``off''
281 conf['rts_threshold'] = '2347'
282 conf['fragm_threshold'] = '2346'
283 conf['driver'] = self.hostapd['driver']
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700284 conf['ssid'] = self._build_ssid('')
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700285 return conf
286
287
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700288 def _build_ssid(self, suffix):
Christopher Wiley3166e432013-08-06 09:53:12 -0700289 unique_salt = ''.join([random.choice(self.SUFFIX_LETTERS)
290 for x in range(5)])
291 return (self.ssid_prefix + unique_salt + suffix)[-32:]
292
293
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700294 def hostap_configure(self, configuration, multi_interface=None):
295 """Build up a hostapd configuration file and start hostapd.
296
297 Also setup a local server if this router supports them.
298
299 @param configuration HosetapConfig object.
300 @param multi_interface bool True iff multiple interfaces allowed.
301
302 """
303 if multi_interface is None and (self.hostapd['configured'] or
304 self.station['configured']):
305 self.deconfig()
306 # Start with the default hostapd config parameters.
307 conf = self.__get_default_hostap_config()
Christopher Wiley3166e432013-08-06 09:53:12 -0700308 conf['ssid'] = (configuration.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700309 self._build_ssid(configuration.ssid_suffix))
Christopher Wiley9b406202013-05-06 14:07:49 -0700310 if configuration.bssid:
311 conf['bssid'] = configuration.bssid
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700312 conf['channel'] = configuration.channel
313 self.hostapd['frequency'] = configuration.frequency
314 conf['hw_mode'] = configuration.hw_mode
315 if configuration.hide_ssid:
316 conf['ignore_broadcast_ssid'] = 1
317 if configuration.is_11n:
318 conf['ieee80211n'] = 1
Christopher Wiley32fbb7a2013-09-18 14:30:50 -0700319 conf['ht_capab'] = configuration.hostapd_ht_capabilities
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700320 if configuration.wmm_enabled:
321 conf['wmm_enabled'] = 1
322 if configuration.require_ht:
323 conf['require_ht'] = 1
Christopher Wiley9fa7c632013-05-01 11:58:06 -0700324 if configuration.beacon_interval:
325 conf['beacon_int'] = configuration.beacon_interval
Christopher Wileya51258e2013-05-03 13:05:06 -0700326 if configuration.dtim_period:
327 conf['dtim_period'] = configuration.dtim_period
Christopher Wileye1235b62013-05-03 15:09:34 -0700328 if configuration.frag_threshold:
329 conf['fragm_threshold'] = configuration.frag_threshold
Christopher Wileyebdc27d2013-06-28 14:35:41 -0700330 if configuration.pmf_support:
331 conf['ieee80211w'] = configuration.pmf_support
Paul Stewart4ae471e2013-09-04 15:42:35 -0700332 if configuration.obss_interval:
333 conf['obss_interval'] = configuration.obss_interval
Christopher Wileyb8921c72013-06-13 09:51:47 -0700334 conf.update(configuration.get_security_hostapd_conf())
Christopher Wileya89706d2013-06-12 13:20:58 -0700335
Wade Guthriefcaaf022013-09-06 11:12:22 -0700336 # TODO(wiley): Remove this multi_interface flag when the bridge router
337 # class is gone.
338 params = {'multi_interface': 1} if multi_interface else {}
339 self.start_hostapd(conf, params)
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700340 # Configure transmit power
341 tx_power_params = {'interface': conf['interface']}
342 # TODO(wiley) support for setting transmit power
343 self.set_txpower(tx_power_params)
344 if self.force_local_server:
345 self.start_local_server(conf['interface'])
Wade Guthriefcaaf022013-09-06 11:12:22 -0700346 self._post_start_hook(params)
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700347 logging.info('AP configured.')
348 self.hostapd['configured'] = True
349
350
Paul Stewartc2b3de82011-03-03 14:45:31 -0800351 def hostap_config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700352 """Configure the AP per test requirements.
Sam Leffler6969d1d2010-03-15 16:07:11 -0700353
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700354 @param params dict of site_wifitest parameters.
355
356 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700357 # keep parameter modifications local-only
358 orig_params = params
359 params = params.copy()
360
Paul Stewart45338d22010-10-21 10:57:02 -0700361 multi_interface = 'multi_interface' in params
362 if multi_interface:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700363 # remove non-hostapd config item from params
Paul Stewart45338d22010-10-21 10:57:02 -0700364 params.pop('multi_interface')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800365 elif self.hostapd['configured'] or self.station['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700366 self.deconfig()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700367
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700368 local_server = params.pop('local_server', False)
369
Christopher Wiley7d414cc2013-04-17 17:26:32 -0700370 conf = self.__get_default_hostap_config()
Paul Stewartc2b3de82011-03-03 14:45:31 -0800371 tx_power_params = {}
372 htcaps = set()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700373
Paul Stewartc2b3de82011-03-03 14:45:31 -0800374 for k, v in params.iteritems():
375 if k == 'ssid':
376 conf['ssid'] = v
377 elif k == 'ssid_suffix':
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700378 conf['ssid'] = self._build_ssid(v)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800379 elif k == 'channel':
380 freq = int(v)
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700381 self.hostapd['frequency'] = freq
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700382
Paul Stewartc2b3de82011-03-03 14:45:31 -0800383 # 2.4GHz
384 if freq <= 2484:
385 # Make sure hw_mode is set
386 if conf.get('hw_mode') == 'a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700387 conf['hw_mode'] = 'g'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800388
389 # Freq = 5 * chan + 2407, except channel 14
390 if freq == 2484:
391 conf['channel'] = 14
392 else:
393 conf['channel'] = (freq - 2407) / 5
394 # 5GHz
Sam Leffler6969d1d2010-03-15 16:07:11 -0700395 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800396 # Make sure hw_mode is set
397 conf['hw_mode'] = 'a'
398 # Freq = 5 * chan + 4000
399 if freq < 5000:
400 conf['channel'] = (freq - 4000) / 5
401 # Freq = 5 * chan + 5000
402 else:
403 conf['channel'] = (freq - 5000) / 5
Sam Leffler6969d1d2010-03-15 16:07:11 -0700404
Paul Stewartc2b3de82011-03-03 14:45:31 -0800405 elif k == 'country':
406 conf['country_code'] = v
407 elif k == 'dotd':
408 conf['ieee80211d'] = 1
409 elif k == '-dotd':
410 conf['ieee80211d'] = 0
411 elif k == 'mode':
412 if v == '11a':
413 conf['hw_mode'] = 'a'
414 elif v == '11g':
415 conf['hw_mode'] = 'g'
416 elif v == '11b':
417 conf['hw_mode'] = 'b'
418 elif v == '11n':
419 conf['ieee80211n'] = 1
420 elif k == 'bintval':
421 conf['beacon_int'] = v
422 elif k == 'dtimperiod':
423 conf['dtim_period'] = v
424 elif k == 'rtsthreshold':
425 conf['rts_threshold'] = v
426 elif k == 'fragthreshold':
427 conf['fragm_threshold'] = v
428 elif k == 'shortpreamble':
429 conf['preamble'] = 1
430 elif k == 'authmode':
431 if v == "open":
432 conf['auth_algs'] = 1
433 elif v == "shared":
434 conf['auth_algs'] = 2
435 elif k == 'hidessid':
436 conf['ignore_broadcast_ssid'] = 1
437 elif k == 'wme':
438 conf['wmm_enabled'] = 1
439 elif k == '-wme':
440 conf['wmm_enabled'] = 0
441 elif k == 'deftxkey':
442 conf['wep_default_key'] = v
443 elif k == 'ht20':
444 htcaps.add('') # NB: ensure 802.11n setup below
445 conf['wmm_enabled'] = 1
446 elif k == 'ht40':
447 htcaps.add('[HT40-]')
448 htcaps.add('[HT40+]')
449 conf['wmm_enabled'] = 1
Paul Stewartc1df8d62011-04-07 14:28:15 -0700450 elif k in ('ht40+', 'ht40-'):
451 htcaps.add('[%s]' % k.upper())
452 conf['wmm_enabled'] = 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800453 elif k == 'shortgi':
454 htcaps.add('[SHORT-GI-20]')
455 htcaps.add('[SHORT-GI-40]')
456 elif k == 'pureg':
457 pass # TODO(sleffler) need hostapd support
458 elif k == 'puren':
459 pass # TODO(sleffler) need hostapd support
460 elif k == 'protmode':
461 pass # TODO(sleffler) need hostapd support
462 elif k == 'ht':
463 htcaps.add('') # NB: ensure 802.11n setup below
464 elif k == 'htprotmode':
465 pass # TODO(sleffler) need hostapd support
466 elif k == 'rifs':
467 pass # TODO(sleffler) need hostapd support
468 elif k == 'wepmode':
469 pass # NB: meaningless for hostapd; ignore
470 elif k == '-ampdu':
471 pass # TODO(sleffler) need hostapd support
472 elif k == 'txpower':
473 tx_power_params['power'] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700474 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800475 conf[k] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700476
Paul Stewartc2b3de82011-03-03 14:45:31 -0800477 # Aggregate ht_capab.
478 if htcaps:
479 conf['ieee80211n'] = 1
480 conf['ht_capab'] = ''.join(htcaps)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700481
Paul Stewart548cf452012-11-27 17:46:23 -0800482 self.start_hostapd(conf, orig_params)
Paul Stewart1ae854b2011-02-08 15:10:14 -0800483
Paul Stewartc2b3de82011-03-03 14:45:31 -0800484 # Configure transmit power
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700485 tx_power_params['interface'] = conf['interface']
Paul Stewartc2b3de82011-03-03 14:45:31 -0800486 self.set_txpower(tx_power_params)
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700487
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700488 if self.force_local_server or local_server is not False:
489 self.start_local_server(conf['interface'])
Sam Leffler6969d1d2010-03-15 16:07:11 -0700490
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700491 self._post_start_hook(orig_params)
492
493 logging.info("AP configured.")
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700494 self.hostapd['configured'] = True
Sam Leffler6969d1d2010-03-15 16:07:11 -0700495
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700496
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700497 @staticmethod
498 def ip_addr(netblock, idx):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700499 """Simple IPv4 calculator.
500
501 Takes host address in "IP/bits" notation and returns netmask, broadcast
502 address as well as integer offsets into the address range.
503
504 @param netblock string host address in "IP/bits" notation.
505 @param idx string describing what to return.
506 @return string containing something you hopefully requested.
507
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700508 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700509 addr_str,bits = netblock.split('/')
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700510 addr = map(int, addr_str.split('.'))
511 mask_bits = (-1 << (32-int(bits))) & 0xffffffff
512 mask = [(mask_bits >> s) & 0xff for s in range(24, -1, -8)]
Paul Stewart5977da92011-06-01 19:14:08 -0700513 if idx == 'local':
514 return addr_str
515 elif idx == 'netmask':
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700516 return '.'.join(map(str, mask))
517 elif idx == 'broadcast':
518 offset = [m ^ 0xff for m in mask]
519 else:
520 offset = [(idx >> s) & 0xff for s in range(24, -1, -8)]
521 return '.'.join(map(str, [(a & m) + o
522 for a, m, o in zip(addr, mask, offset)]))
523
524
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700525 def ibss_configure(self, config):
526 """Configure a station based AP in IBSS mode.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700527
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700528 Extract relevant configuration objects from |config| despite not
529 actually being a hostap managed endpoint.
530
531 @param config HostapConfig object.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700532
533 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700534 if self.station['configured'] or self.hostapd['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700535 self.deconfig()
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700536 interface = self._get_wlanif(config.frequency, self.phytype,
537 config.hw_mode)
Christopher Wiley3166e432013-08-06 09:53:12 -0700538 self.station['conf']['ssid'] = (config.ssid or
Christopher Wiley0ff28ab2013-08-12 13:23:04 -0700539 self._build_ssid(config.ssid_suffix))
Paul Stewartc2b3de82011-03-03 14:45:31 -0800540 # Connect the station
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700541 self.router.run('%s link set %s up' % (self.cmd_ip, interface))
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700542 self.iw_runner.ibss_join(
543 interface, self.station['conf']['ssid'], config.frequency)
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700544 # Always start a local server.
545 self.start_local_server(interface)
546 # Remember that this interface is up.
Paul Stewartc2b3de82011-03-03 14:45:31 -0800547 self.station['configured'] = True
548 self.station['interface'] = interface
549
550
Paul Stewart2bd823b2012-11-21 15:03:37 -0800551 def local_server_address(self, index):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700552 """Get the local server address for an interface.
553
554 When we multiple local servers, we give them static IP addresses
Christopher Wileyb1ade0a2013-09-16 13:09:55 -0700555 like 192.168.*.254.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700556
557 @param index int describing which local server this is for.
558
559 """
Christopher Wileyb1ade0a2013-09-16 13:09:55 -0700560 return '%d.%d.%d.%d' % (self.SUBNET_PREFIX_OCTETS + (index, 254))
Paul Stewart2bd823b2012-11-21 15:03:37 -0800561
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700562
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700563 def start_local_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700564 """Start a local server on an interface.
565
566 @param interface string (e.g. wlan0)
567
568 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700569 logging.info("Starting up local server...")
570
571 if len(self.local_servers) >= 256:
572 raise error.TestFail('Exhausted available local servers')
573
Paul Stewart2bd823b2012-11-21 15:03:37 -0800574 netblock = '%s/24' % self.local_server_address(len(self.local_servers))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700575
576 params = {}
577 params['netblock'] = netblock
578 params['subnet'] = self.ip_addr(netblock, 0)
579 params['netmask'] = self.ip_addr(netblock, 'netmask')
580 params['dhcp_range'] = ' '.join(
581 (self.ip_addr(netblock, self.dhcp_low),
582 self.ip_addr(netblock, self.dhcp_high)))
mukesh agrawal05c455a2011-10-12 13:40:27 -0700583 params['interface'] = interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700584
585 params['ip_params'] = ("%s broadcast %s dev %s" %
586 (netblock,
587 self.ip_addr(netblock, 'broadcast'),
588 interface))
589 self.local_servers.append(params)
590
591 self.router.run("%s addr flush %s" %
592 (self.cmd_ip, interface))
593 self.router.run("%s addr add %s" %
594 (self.cmd_ip, params['ip_params']))
595 self.router.run("%s link set %s up" %
596 (self.cmd_ip, interface))
Paul Stewart548cf452012-11-27 17:46:23 -0800597 self.start_dhcp_server(interface)
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700598
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700599
Paul Stewart548cf452012-11-27 17:46:23 -0800600 def start_dhcp_server(self, interface):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700601 """Start a dhcp server on an interface.
602
603 @param interface string (e.g. wlan0)
604
605 """
Paul Stewart326badb2012-12-18 14:18:54 -0800606 conf_file = self.dhcpd_conf % interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700607 dhcp_conf = '\n'.join(map(
608 lambda server_conf: \
609 "subnet %(subnet)s netmask %(netmask)s {\n" \
610 " range %(dhcp_range)s;\n" \
611 "}" % server_conf,
612 self.local_servers))
613 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
Paul Stewart326badb2012-12-18 14:18:54 -0800614 (conf_file,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700615 '\n'.join(('ddns-update-style none;', dhcp_conf))))
616 self.router.run("touch %s" % self.dhcpd_leases)
617
618 self.router.run("pkill dhcpd >/dev/null 2>&1", ignore_status=True)
619 self.router.run("%s -q -cf %s -lf %s" %
Paul Stewart326badb2012-12-18 14:18:54 -0800620 (self.cmd_dhcpd, conf_file, self.dhcpd_leases))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700621
622
Paul Stewart326badb2012-12-18 14:18:54 -0800623 def stop_dhcp_server(self, instance=None):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700624 """Stop a dhcp server on the router.
625
626 @param instance string instance to kill.
627
628 """
Paul Stewart326badb2012-12-18 14:18:54 -0800629 self._kill_process_instance('dhcpd', instance, 0)
630
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700631
Paul Stewart548cf452012-11-27 17:46:23 -0800632 def stop_dhcp_servers(self):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700633 """Stop all dhcp servers on the router."""
Paul Stewart326badb2012-12-18 14:18:54 -0800634 self.stop_dhcp_server(None)
Paul Stewart548cf452012-11-27 17:46:23 -0800635
636
Paul Stewartc2b3de82011-03-03 14:45:31 -0800637 def config(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700638 """Configure an AP based on site_wifitest parameters.
639
640 @param params dict of site_wifitest parameters.
641
642 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800643 if self.apmode:
644 self.hostap_config(params)
645 else:
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700646 config = hostap_config.HostapConfig(
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700647 frequency=int(params.get('channel', None)))
648 self.ibss_configure(config)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800649
650
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700651 def get_wifi_ip(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700652 """Return IP address on the WiFi subnet of a local server on the router.
653
654 If no local servers are configured (e.g. for an RSPro), a TestFail will
655 be raised.
656
657 @param ap_num int which local server to get an address from.
658
659 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700660 if self.local_servers:
661 return self.ip_addr(self.local_servers[ap_num]['netblock'],
662 'local')
663 else:
664 raise error.TestFail("No IP address assigned")
Paul Stewart5977da92011-06-01 19:14:08 -0700665
666
Paul Stewart17350be2012-12-14 13:34:54 -0800667 def get_hostapd_mac(self, ap_num):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700668 """Return the MAC address of an AP in the test.
669
670 @param ap_num int index of local server to read the MAC address from.
671 @return string MAC address like 00:11:22:33:44:55.
672
673 """
Paul Stewart17350be2012-12-14 13:34:54 -0800674 instance = self.hostapd_instances[ap_num]
675 interface = instance['interface']
676 result = self.router.run('%s addr show %s' % (self.cmd_ip, interface))
677 # Example response:
678 # 1: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 UP qlen 1000
679 # link/ether 99:88:77:66:55:44 brd ff:ff:ff:ff:ff:ff
680 # inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
681 # inet6 fe80::6a7f:74ff:fe66:5544/64 scope link
682 # we want the MAC address after the "link/ether" above.
683 parts = result.stdout.split(' ')
684 return parts[parts.index('link/ether') + 1]
685
686
Christopher Wileyd89b5282013-04-10 15:21:26 -0700687 def deconfig(self, params={}):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700688 """De-configure the AP (will also bring wlan down).
Sam Leffler6969d1d2010-03-15 16:07:11 -0700689
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700690 @param params dict of parameters from site_wifitest.
691
692 """
Christopher Wiley4cd4b3f2013-11-11 17:27:28 -0800693 self.deconfig_aps(instance=params.get('instance', None),
694 silent='silent' in params)
695
696
697 def deconfig_aps(self, instance=None, silent=False):
698 """De-configure an AP (will also bring wlan down).
699
700 @param instance: int or None. If instance is None, will bring down all
701 instances of hostapd.
702 @param silent: True if instances should be brought without de-authing
703 the DUT.
704
705 """
Paul Stewartc2b3de82011-03-03 14:45:31 -0800706 if not self.hostapd['configured'] and not self.station['configured']:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700707 return
Sam Leffler6969d1d2010-03-15 16:07:11 -0700708
Paul Stewartc2b3de82011-03-03 14:45:31 -0800709 if self.hostapd['configured']:
Paul Stewart326badb2012-12-18 14:18:54 -0800710 local_servers = []
Christopher Wiley4cd4b3f2013-11-11 17:27:28 -0800711 if instance is not None:
712 instances = [ self.hostapd_instances.pop(instance) ]
Paul Stewart326badb2012-12-18 14:18:54 -0800713 for server in self.local_servers:
714 if server['interface'] == instances[0]['interface']:
715 local_servers = [server]
716 self.local_servers.remove(server)
717 break
Paul Stewart21737812012-12-06 11:03:32 -0800718 else:
719 instances = self.hostapd_instances
720 self.hostapd_instances = []
Paul Stewart326badb2012-12-18 14:18:54 -0800721 local_servers = self.local_servers
722 self.local_servers = []
Paul Stewart64cc4292011-06-01 10:59:36 -0700723
Paul Stewart21737812012-12-06 11:03:32 -0800724 for instance in instances:
Christopher Wiley4cd4b3f2013-11-11 17:27:28 -0800725 if silent:
Paul Stewart21737812012-12-06 11:03:32 -0800726 # Deconfigure without notifying DUT. Remove the interface
727 # hostapd uses to send beacon and DEAUTH packets.
728 self._remove_interface(instance['interface'], True)
729
Paul Stewart326badb2012-12-18 14:18:54 -0800730 self.kill_hostapd_instance(instance['conf_file'])
Christopher Wiley7337ff62013-10-03 17:21:46 -0700731 if wifi_test_utils.is_installed(self.host,
732 instance['log_file']):
733 self.router.get_file(instance['log_file'],
734 'debug/hostapd_router_%d_%s.log' %
735 (self.hostapd['log_count'],
736 instance['interface']))
737 else:
738 logging.error('Did not collect hostapd log file because '
739 'it was missing.')
Paul Stewart548cf452012-11-27 17:46:23 -0800740 self._release_wlanif(instance['interface'])
741# self.router.run("rm -f %(log_file)s %(conf_file)s" % instance)
Paul Stewartf854d2e2011-05-04 13:19:18 -0700742 self.hostapd['log_count'] += 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800743 if self.station['configured']:
Christopher Wiley05262d62013-04-17 17:53:59 -0700744 local_servers = self.local_servers
745 self.local_servers = []
Paul Stewartc2b3de82011-03-03 14:45:31 -0800746 if self.station['type'] == 'ibss':
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700747 self.iw_runner.ibss_leave(self.station['interface'])
Paul Stewartc2b3de82011-03-03 14:45:31 -0800748 else:
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700749 self.iw_runner.disconnect_station(self.station['interface'])
Paul Stewartc2b3de82011-03-03 14:45:31 -0800750 self.router.run("%s link set %s down" % (self.cmd_ip,
751 self.station['interface']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700752
Paul Stewart326badb2012-12-18 14:18:54 -0800753 for server in local_servers:
754 self.stop_dhcp_server(server['interface'])
755 self.router.run("%s addr del %s" %
756 (self.cmd_ip, server['ip_params']),
757 ignore_status=True)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700758
759 self.hostapd['configured'] = False
Paul Stewartc2b3de82011-03-03 14:45:31 -0800760 self.station['configured'] = False
Paul Stewart7cb1f062010-06-10 15:46:20 -0700761
762
Paul Stewart17350be2012-12-14 13:34:54 -0800763 def verify_pmksa_auth(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700764 """Verify that the PMKSA auth was cached on a hostapd instance.
765
766 @param params dict with optional key 'instance' (defaults to 0).
767
768 """
Paul Stewart17350be2012-12-14 13:34:54 -0800769 instance_num = params.get('instance', 0)
770 instance = self.hostapd_instances[instance_num]
771 pmksa_match = 'PMK from PMKSA cache - skip IEEE 802.1X.EAP'
772 self.router.run('grep -q "%s" %s' % (pmksa_match, instance['log_file']))
773
774
Christopher Wileye0afecb2013-11-11 10:54:23 -0800775 def get_ssid(self, instance=None):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700776 """@return string ssid for the network stemming from this router."""
Christopher Wileye0afecb2013-11-11 10:54:23 -0800777 if instance is None:
778 instance = 0
779 if len(self.hostapd_instances) > 1:
780 raise error.TestFail('No instance of hostapd specified with '
781 'multiple instances present.')
782
Christopher Wiley3099be72013-11-06 16:49:02 -0800783 if self.hostapd_instances:
784 return self.hostapd_instances[instance]['ssid']
Christopher Wiley1febd6a2013-06-03 13:59:48 -0700785
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')
Christopher Wiley7bd2e082013-10-16 17:40:40 -0700805 self.iw_runner.set_tx_power(interface, power)
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700806
807
Wade Guthriee4074dd2013-10-30 11:00:48 -0700808 def deauth_client(self, client_mac):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700809 """Deauthenticates a client described in params.
810
Wade Guthriee4074dd2013-10-30 11:00:48 -0700811 @param client_mac string containing the mac address of the client to be
812 deauthenticated.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700813
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'],
Wade Guthriee4074dd2013-10-30 11:00:48 -0700818 client_mac))
819
820
821 @base_utils.deprecated
822 def deauth(self, params):
823 """Deauthenticates a client described in params.
824
825 Deprecated: Call 'deauth_client', instead.
826
827 @param params dict containing a key 'client'.
828
829 """
830 self.deauth_client(params['client'])
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700831
832
Paul Stewart51b0f382013-06-12 09:03:02 -0700833 def send_management_frame(self, frame_type, instance=0):
834 """Injects a management frame into an active hostapd session.
835
836 @param frame_type string the type of frame to send.
837 @param instance int indicating which hostapd instance to inject into.
838
839 """
840 hostap_interface = self.hostapd_instances[instance]['interface']
841 interface = self._get_wlanif(0, 'monitor', same_phy_as=hostap_interface)
842 self.router.run("%s link set %s up" % (self.cmd_ip, interface))
843 self.router.run('%s %s %s' %
844 (self.cmd_send_management_frame, interface, frame_type))
845 self._release_wlanif(interface)
846
847
Paul Stewart25536942013-08-15 17:33:42 -0700848 def detect_client_deauth(self, client_mac, instance=0):
849 """Detects whether hostapd has logged a deauthentication from
850 |client_mac|.
851
852 @param client_mac string the MAC address of the client to detect.
853 @param instance int indicating which hostapd instance to query.
854
855 """
856 interface = self.hostapd_instances[instance]['interface']
857 deauth_msg = "%s: deauthentication: STA=%s" % (interface, client_mac)
858 log_file = self.hostapd_instances[instance]['log_file']
859 result = self.router.run("grep -qi '%s' %s" % (deauth_msg, log_file),
860 ignore_status=True)
861 return result.exit_status == 0
862
863
Paul Stewart4ae471e2013-09-04 15:42:35 -0700864 def detect_client_coexistence_report(self, client_mac, instance=0):
865 """Detects whether hostapd has logged an action frame from
866 |client_mac| indicating information about 20/40MHz BSS coexistence.
867
868 @param client_mac string the MAC address of the client to detect.
869 @param instance int indicating which hostapd instance to query.
870
871 """
872 coex_msg = ('nl80211: MLME event frame - hexdump(len=.*): '
873 '.. .. .. .. .. .. .. .. .. .. %s '
874 '.. .. .. .. .. .. .. .. 04 00.*48 01 ..' %
875 ' '.join(client_mac.split(':')))
876 log_file = self.hostapd_instances[instance]['log_file']
877 result = self.router.run("grep -qi '%s' %s" % (coex_msg, log_file),
878 ignore_status=True)
879 return result.exit_status == 0
880
881
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700882 def _pre_config_hook(self, config):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700883 """Hook for subclasses.
884
885 Run after gathering configuration parameters,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700886 but before writing parameters to config file.
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700887
888 @param config dict containing hostapd config parameters.
889
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700890 """
891 pass
892
893
894 def _pre_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700895 """Hook for subclasses.
896
897 Run after generating hostapd config file, but before starting hostapd.
898
899 @param params dict parameters from site_wifitest.
900
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700901 """
902 pass
903
904
905 def _post_start_hook(self, params):
Christopher Wileyf99e6cc2013-04-19 10:12:43 -0700906 """Hook for subclasses run after starting hostapd.
907
908 @param params dict parameters from site_wifitest.
909
910 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700911 pass