blob: d640015982e4a2686176a6872dcd35801b7c96e6 [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
6import re
7
Paul Stewartc9628b32010-08-11 13:03:51 -07008from autotest_lib.client.common_lib import error
Paul Stewart2ee7fdf2011-05-19 16:29:23 -07009from autotest_lib.server import site_linux_system
Sam Leffler19bb0a72010-04-12 08:51:08 -070010
11def isLinuxRouter(router):
12 router_uname = router.run('uname').stdout
13 return re.search('Linux', router_uname)
14
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070015class LinuxRouter(site_linux_system.LinuxSystem):
Sam Leffler6969d1d2010-03-15 16:07:11 -070016 """
17 Linux/mac80211-style WiFi Router support for WiFiTest class.
18
19 This class implements test methods/steps that communicate with a
20 router implemented with Linux/mac80211. The router must
21 be pre-configured to enable ssh access and have a mac80211-based
22 wireless device. We also assume hostapd 0.7.x and iw are present
23 and any necessary modules are pre-loaded.
24 """
25
26
27 def __init__(self, host, params, defssid):
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070028 site_linux_system.LinuxSystem.__init__(self, host, params, "router")
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070029 self._remove_interfaces()
Paul Stewart2ee7fdf2011-05-19 16:29:23 -070030
Wade Guthrie24d1e312012-04-24 16:53:40 -070031 # Router host.
32 self.router = host
33
34 self.cmd_hostapd = self.__must_be_installed(host,
35 params.get("cmd_hostapd", "/usr/sbin/hostapd"))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070036 self.cmd_hostapd_cli = \
37 params.get("cmd_hostapd_cli", "/usr/sbin/hostapd_cli")
Paul Stewart326badb2012-12-18 14:18:54 -080038 self.dhcpd_conf = "/tmp/dhcpd.%s.conf"
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070039 self.dhcpd_leases = "/tmp/dhcpd.leases"
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070040
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070041 # hostapd configuration persists throughout the test, subsequent
42 # 'config' commands only modify it.
Paul Stewart7cb1f062010-06-10 15:46:20 -070043 self.defssid = defssid
Paul Stewartd5aafa92013-03-24 19:06:14 -070044 self.default_config = {
45 'ssid': defssid,
46 'hw_mode': 'g',
47 'ctrl_interface': '/tmp/hostapd-test.control',
48 'logger_syslog': '-1',
49 'logger_syslog_level': '0'
50 }
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070051 self.hostapd = {
52 'configured': False,
Paul Stewart326badb2012-12-18 14:18:54 -080053 'config_file': "/tmp/hostapd-test-%s.conf",
54 'log_file': "/tmp/hostapd-test-%s.log",
Paul Stewartf854d2e2011-05-04 13:19:18 -070055 'log_count': 0,
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070056 'driver': "nl80211",
Paul Stewartd5aafa92013-03-24 19:06:14 -070057 'conf': self.default_config.copy()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070058 }
Paul Stewartc2b3de82011-03-03 14:45:31 -080059 self.station = {
60 'configured': False,
61 'conf': {
62 'ssid': defssid,
Paul Stewartf05d7fd2011-04-06 16:19:37 -070063 },
Paul Stewartc2b3de82011-03-03 14:45:31 -080064 }
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070065 self.local_servers = []
Paul Stewart548cf452012-11-27 17:46:23 -080066 self.hostapd_instances = []
mukesh agrawalfe0e85b2011-08-09 14:24:15 -070067 self.force_local_server = "force_local_server" in params
68 self.dhcp_low = 1
69 self.dhcp_high = 128
Paul Stewartf05d7fd2011-04-06 16:19:37 -070070
Paul Stewart548cf452012-11-27 17:46:23 -080071 # Kill hostapd and dhcp server if already running.
Thieu Le7b23a542012-01-27 15:54:48 -080072 self.kill_hostapd()
Paul Stewart548cf452012-11-27 17:46:23 -080073 self.stop_dhcp_servers()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070074
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -070075 # Place us in the US by default
76 self.router.run("%s reg set US" % self.cmd_iw)
Sam Leffler6969d1d2010-03-15 16:07:11 -070077
Wade Guthrie24d1e312012-04-24 16:53:40 -070078 def __must_be_installed(self, host, cmd):
79 if not self.__is_installed(host, cmd):
80 raise error.TestFail('Unable to find %s on %s' % (cmd, host.ip))
81 return cmd
82
83 def __is_installed(self, host, filename):
84 result = host.run("ls %s" % filename, ignore_status=True)
85 m = re.search(filename, result.stdout)
86 return m is not None
87
Paul Stewartf05d7fd2011-04-06 16:19:37 -070088
Sam Leffler6969d1d2010-03-15 16:07:11 -070089 def create(self, params):
Christopher Wiley14796b32013-04-03 14:53:33 -070090 """
91 Create a wifi device of the specified type.
92
93 @param params dict containing the device type under key 'type'.
94
95 """
96 self.create_wifi_device(params['type'])
97
98
99 def create_wifi_device(self, device_type='hostap'):
100 """
101 Create a wifi device of the specified type.
102
103 Defaults to creating a hostap managed device.
104
105 @param device_type string device type.
106
107 """
Sam Leffler6969d1d2010-03-15 16:07:11 -0700108 #
109 # AP mode is handled entirely by hostapd so we only
110 # have to setup others (mapping the bsd type to what
111 # iw wants)
112 #
113 # map from bsd types to iw types
Christopher Wiley14796b32013-04-03 14:53:33 -0700114 self.apmode = device_type in ('ap', 'hostap')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800115 if not self.apmode:
Christopher Wiley14796b32013-04-03 14:53:33 -0700116 self.station['type'] = device_type
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700117 self.phytype = {
Christopher Wiley14796b32013-04-03 14:53:33 -0700118 'sta' : 'managed',
119 'monitor' : 'monitor',
120 'adhoc' : 'adhoc',
121 'ibss' : 'ibss',
122 'ap' : 'managed', # NB: handled by hostapd
123 'hostap' : 'managed', # NB: handled by hostapd
124 'mesh' : 'mesh',
125 'wds' : 'wds',
126 }[device_type]
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700127
Sam Leffler6969d1d2010-03-15 16:07:11 -0700128
Christopher Wileyd89b5282013-04-10 15:21:26 -0700129 def destroy(self, params={}):
Sam Leffler6969d1d2010-03-15 16:07:11 -0700130 """ Destroy a previously created device """
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700131 self.deconfig(params)
Paul Stewartd5aafa92013-03-24 19:06:14 -0700132 self.hostapd['conf'] = self.default_config.copy()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700133
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700134 def has_local_server(self):
135 return bool(self.local_servers)
Sam Leffler6969d1d2010-03-15 16:07:11 -0700136
Paul Stewart9e3ff0b2011-08-17 20:35:19 -0700137 def cleanup(self, params):
138 """ Clean up any resources in use """
139 # For linux, this is a no-op
140 pass
141
Paul Stewart548cf452012-11-27 17:46:23 -0800142 def start_hostapd(self, conf, params):
Paul Stewart548cf452012-11-27 17:46:23 -0800143 # Figure out the correct interface.
Paul Stewart326badb2012-12-18 14:18:54 -0800144 interface = self._get_wlanif(self.hostapd['frequency'],
145 self.phytype,
146 mode=conf.get('hw_mode', 'b'))
147
148 conf_file = self.hostapd['config_file'] % interface
149 log_file = self.hostapd['log_file'] % interface
150 conf['interface'] = interface
Paul Stewart548cf452012-11-27 17:46:23 -0800151
152 # Generate hostapd.conf.
153 self._pre_config_hook(conf)
154 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
155 (conf_file, '\n'.join(
156 "%s=%s" % kv for kv in conf.iteritems())))
157
158 # Run hostapd.
159 logging.info("Starting hostapd...")
160 self._pre_start_hook(params)
161 self.router.run("%s -dd %s &> %s &" %
162 (self.cmd_hostapd, conf_file, log_file))
163
164 self.hostapd_instances.append({
165 'conf_file': conf_file,
166 'log_file': log_file,
Paul Stewart326badb2012-12-18 14:18:54 -0800167 'interface': interface
Paul Stewart548cf452012-11-27 17:46:23 -0800168 })
169
Paul Stewart326badb2012-12-18 14:18:54 -0800170 def _kill_process_instance(self, process, instance=None, wait=0):
Thieu Le7b23a542012-01-27 15:54:48 -0800171 """
Paul Stewart326badb2012-12-18 14:18:54 -0800172 Kills program named |process|, optionally only a specific
173 |instance|. If |wait| is specified, we makes sure |process| exits
174 before returning.
Thieu Le7b23a542012-01-27 15:54:48 -0800175 """
Paul Stewart21737812012-12-06 11:03:32 -0800176 if instance:
Paul Stewart326badb2012-12-18 14:18:54 -0800177 search_arg = '-f "%s.*%s"' % (process, instance)
Paul Stewart21737812012-12-06 11:03:32 -0800178 else:
Paul Stewart326badb2012-12-18 14:18:54 -0800179 search_arg = process
Paul Stewart21737812012-12-06 11:03:32 -0800180
Paul Stewart326badb2012-12-18 14:18:54 -0800181 cmd = "pkill %s >/dev/null 2>&1" % search_arg
182
183 if wait:
184 cmd += (" && while pgrep %s &> /dev/null; do sleep 1; done" %
185 search_arg)
186 self.router.run(cmd, timeout=wait, ignore_status=True)
187 else:
188 self.router.run(cmd, ignore_status=True)
189
190 def kill_hostapd_instance(self, instance):
191 self._kill_process_instance('hostapd', instance, 30)
Thieu Le7b23a542012-01-27 15:54:48 -0800192
Paul Stewart21737812012-12-06 11:03:32 -0800193 def kill_hostapd(self):
194 self.kill_hostapd_instance(None)
195
Paul Stewartc2b3de82011-03-03 14:45:31 -0800196 def hostap_config(self, params):
Sam Leffler6969d1d2010-03-15 16:07:11 -0700197 """ Configure the AP per test requirements """
198
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700199 # keep parameter modifications local-only
200 orig_params = params
201 params = params.copy()
202
Paul Stewart45338d22010-10-21 10:57:02 -0700203 multi_interface = 'multi_interface' in params
204 if multi_interface:
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700205 # remove non-hostapd config item from params
Paul Stewart45338d22010-10-21 10:57:02 -0700206 params.pop('multi_interface')
Paul Stewartc2b3de82011-03-03 14:45:31 -0800207 elif self.hostapd['configured'] or self.station['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700208 self.deconfig()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700209
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700210 local_server = params.pop('local_server', False)
211
Paul Stewartc2b3de82011-03-03 14:45:31 -0800212 # Construct the hostapd.conf file and start hostapd.
213 conf = self.hostapd['conf']
Sam Lefflerbf5af622011-10-21 12:11:17 -0700214 # default RTS and frag threshold to ``off''
215 conf['rts_threshold'] = '2347'
216 conf['fragm_threshold'] = '2346'
217
Paul Stewartc2b3de82011-03-03 14:45:31 -0800218 tx_power_params = {}
219 htcaps = set()
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700220
Paul Stewartc2b3de82011-03-03 14:45:31 -0800221 conf['driver'] = params.get('hostapd_driver',
222 self.hostapd['driver'])
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700223
Paul Stewartc2b3de82011-03-03 14:45:31 -0800224 for k, v in params.iteritems():
225 if k == 'ssid':
226 conf['ssid'] = v
227 elif k == 'ssid_suffix':
Paul Stewart05cebab2012-05-29 11:58:17 -0700228 conf['ssid'] = self.defssid[:(32-len(v))] + v
Paul Stewartc2b3de82011-03-03 14:45:31 -0800229 elif k == 'channel':
230 freq = int(v)
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700231 self.hostapd['frequency'] = freq
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700232
Paul Stewartc2b3de82011-03-03 14:45:31 -0800233 # 2.4GHz
234 if freq <= 2484:
235 # Make sure hw_mode is set
236 if conf.get('hw_mode') == 'a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700237 conf['hw_mode'] = 'g'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800238
239 # Freq = 5 * chan + 2407, except channel 14
240 if freq == 2484:
241 conf['channel'] = 14
242 else:
243 conf['channel'] = (freq - 2407) / 5
244 # 5GHz
Sam Leffler6969d1d2010-03-15 16:07:11 -0700245 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800246 # Make sure hw_mode is set
247 conf['hw_mode'] = 'a'
248 # Freq = 5 * chan + 4000
249 if freq < 5000:
250 conf['channel'] = (freq - 4000) / 5
251 # Freq = 5 * chan + 5000
252 else:
253 conf['channel'] = (freq - 5000) / 5
Sam Leffler6969d1d2010-03-15 16:07:11 -0700254
Paul Stewartc2b3de82011-03-03 14:45:31 -0800255 elif k == 'country':
256 conf['country_code'] = v
257 elif k == 'dotd':
258 conf['ieee80211d'] = 1
259 elif k == '-dotd':
260 conf['ieee80211d'] = 0
261 elif k == 'mode':
262 if v == '11a':
263 conf['hw_mode'] = 'a'
264 elif v == '11g':
265 conf['hw_mode'] = 'g'
266 elif v == '11b':
267 conf['hw_mode'] = 'b'
268 elif v == '11n':
269 conf['ieee80211n'] = 1
270 elif k == 'bintval':
271 conf['beacon_int'] = v
272 elif k == 'dtimperiod':
273 conf['dtim_period'] = v
274 elif k == 'rtsthreshold':
275 conf['rts_threshold'] = v
276 elif k == 'fragthreshold':
277 conf['fragm_threshold'] = v
278 elif k == 'shortpreamble':
279 conf['preamble'] = 1
280 elif k == 'authmode':
281 if v == "open":
282 conf['auth_algs'] = 1
283 elif v == "shared":
284 conf['auth_algs'] = 2
285 elif k == 'hidessid':
286 conf['ignore_broadcast_ssid'] = 1
287 elif k == 'wme':
288 conf['wmm_enabled'] = 1
289 elif k == '-wme':
290 conf['wmm_enabled'] = 0
291 elif k == 'deftxkey':
292 conf['wep_default_key'] = v
293 elif k == 'ht20':
294 htcaps.add('') # NB: ensure 802.11n setup below
295 conf['wmm_enabled'] = 1
296 elif k == 'ht40':
297 htcaps.add('[HT40-]')
298 htcaps.add('[HT40+]')
299 conf['wmm_enabled'] = 1
Paul Stewartc1df8d62011-04-07 14:28:15 -0700300 elif k in ('ht40+', 'ht40-'):
301 htcaps.add('[%s]' % k.upper())
302 conf['wmm_enabled'] = 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800303 elif k == 'shortgi':
304 htcaps.add('[SHORT-GI-20]')
305 htcaps.add('[SHORT-GI-40]')
306 elif k == 'pureg':
307 pass # TODO(sleffler) need hostapd support
308 elif k == 'puren':
309 pass # TODO(sleffler) need hostapd support
310 elif k == 'protmode':
311 pass # TODO(sleffler) need hostapd support
312 elif k == 'ht':
313 htcaps.add('') # NB: ensure 802.11n setup below
314 elif k == 'htprotmode':
315 pass # TODO(sleffler) need hostapd support
316 elif k == 'rifs':
317 pass # TODO(sleffler) need hostapd support
318 elif k == 'wepmode':
319 pass # NB: meaningless for hostapd; ignore
320 elif k == '-ampdu':
321 pass # TODO(sleffler) need hostapd support
322 elif k == 'txpower':
323 tx_power_params['power'] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700324 else:
Paul Stewartc2b3de82011-03-03 14:45:31 -0800325 conf[k] = v
Nebojsa Sabovic60ae1462010-05-07 16:14:45 -0700326
Paul Stewartc2b3de82011-03-03 14:45:31 -0800327 # Aggregate ht_capab.
328 if htcaps:
329 conf['ieee80211n'] = 1
330 conf['ht_capab'] = ''.join(htcaps)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700331
Paul Stewart548cf452012-11-27 17:46:23 -0800332 self.start_hostapd(conf, orig_params)
Paul Stewart1ae854b2011-02-08 15:10:14 -0800333
Paul Stewartc2b3de82011-03-03 14:45:31 -0800334 # Configure transmit power
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700335 tx_power_params['interface'] = conf['interface']
Paul Stewartc2b3de82011-03-03 14:45:31 -0800336 self.set_txpower(tx_power_params)
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700337
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700338 if self.force_local_server or local_server is not False:
339 self.start_local_server(conf['interface'])
Sam Leffler6969d1d2010-03-15 16:07:11 -0700340
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700341 self._post_start_hook(orig_params)
342
343 logging.info("AP configured.")
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700344 self.hostapd['configured'] = True
Sam Leffler6969d1d2010-03-15 16:07:11 -0700345
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700346 @staticmethod
347 def ip_addr(netblock, idx):
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700348 """
349 Simple IPv4 calculator. Takes host address in "IP/bits" notation
350 and returns netmask, broadcast address as well as integer offsets
351 into the address range.
352 """
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700353 addr_str,bits = netblock.split('/')
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700354 addr = map(int, addr_str.split('.'))
355 mask_bits = (-1 << (32-int(bits))) & 0xffffffff
356 mask = [(mask_bits >> s) & 0xff for s in range(24, -1, -8)]
Paul Stewart5977da92011-06-01 19:14:08 -0700357 if idx == 'local':
358 return addr_str
359 elif idx == 'netmask':
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700360 return '.'.join(map(str, mask))
361 elif idx == 'broadcast':
362 offset = [m ^ 0xff for m in mask]
363 else:
364 offset = [(idx >> s) & 0xff for s in range(24, -1, -8)]
365 return '.'.join(map(str, [(a & m) + o
366 for a, m, o in zip(addr, mask, offset)]))
367
368
Paul Stewartc2b3de82011-03-03 14:45:31 -0800369 def station_config(self, params):
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700370 # keep parameter modifications local-only
371 orig_params = params
372 params = params.copy()
373
374 if 'multi_interface' in params:
375 raise NotImplementedError("station with multi_interface")
376
377 if self.station['type'] != 'ibss':
378 raise NotImplementedError("non-ibss station")
379
380 if self.station['configured'] or self.hostapd['configured']:
Christopher Wileyd89b5282013-04-10 15:21:26 -0700381 self.deconfig()
Paul Stewartc2b3de82011-03-03 14:45:31 -0800382
Paul Stewartf05d7fd2011-04-06 16:19:37 -0700383 local_server = params.pop('local_server', False)
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700384 mode = None
Paul Stewartc2b3de82011-03-03 14:45:31 -0800385 conf = self.station['conf']
386 for k, v in params.iteritems():
387 if k == 'ssid_suffix':
388 conf['ssid'] = self.defssid + v
389 elif k == 'channel':
390 freq = int(v)
391 if freq > 2484:
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700392 mode = 'a'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800393 elif k == 'mode':
394 if v == '11a':
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700395 mode = 'a'
Paul Stewartc2b3de82011-03-03 14:45:31 -0800396 else:
397 conf[k] = v
398
Paul Stewart2ee7fdf2011-05-19 16:29:23 -0700399 interface = self._get_wlanif(freq, self.phytype, mode)
400
Paul Stewartc2b3de82011-03-03 14:45:31 -0800401 # Run interface configuration commands
402 for k, v in conf.iteritems():
403 if k != 'ssid':
404 self.router.run("%s dev %s set %s %s" %
405 (self.cmd_iw, interface, k, v))
406
407 # Connect the station
408 self.router.run("%s link set %s up" % (self.cmd_ip, interface))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700409 self.router.run("%s dev %s ibss join %s %d" %
410 (self.cmd_iw, interface, conf['ssid'], freq))
Paul Stewartc2b3de82011-03-03 14:45:31 -0800411
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700412 if self.force_local_server or local_server is not False:
413 self.start_local_server(interface)
Paul Stewartc2b3de82011-03-03 14:45:31 -0800414
415 self.station['configured'] = True
416 self.station['interface'] = interface
417
418
Paul Stewart2bd823b2012-11-21 15:03:37 -0800419 def local_server_address(self, index):
420 return '%d.%d.%d.%d' % (192, 168, index, 254)
421
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700422 def start_local_server(self, interface):
423 logging.info("Starting up local server...")
424
425 if len(self.local_servers) >= 256:
426 raise error.TestFail('Exhausted available local servers')
427
Paul Stewart2bd823b2012-11-21 15:03:37 -0800428 netblock = '%s/24' % self.local_server_address(len(self.local_servers))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700429
430 params = {}
431 params['netblock'] = netblock
432 params['subnet'] = self.ip_addr(netblock, 0)
433 params['netmask'] = self.ip_addr(netblock, 'netmask')
434 params['dhcp_range'] = ' '.join(
435 (self.ip_addr(netblock, self.dhcp_low),
436 self.ip_addr(netblock, self.dhcp_high)))
mukesh agrawal05c455a2011-10-12 13:40:27 -0700437 params['interface'] = interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700438
439 params['ip_params'] = ("%s broadcast %s dev %s" %
440 (netblock,
441 self.ip_addr(netblock, 'broadcast'),
442 interface))
443 self.local_servers.append(params)
444
445 self.router.run("%s addr flush %s" %
446 (self.cmd_ip, interface))
447 self.router.run("%s addr add %s" %
448 (self.cmd_ip, params['ip_params']))
449 self.router.run("%s link set %s up" %
450 (self.cmd_ip, interface))
Paul Stewart548cf452012-11-27 17:46:23 -0800451 self.start_dhcp_server(interface)
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700452
Paul Stewart548cf452012-11-27 17:46:23 -0800453 def start_dhcp_server(self, interface):
Paul Stewart326badb2012-12-18 14:18:54 -0800454 conf_file = self.dhcpd_conf % interface
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700455 dhcp_conf = '\n'.join(map(
456 lambda server_conf: \
457 "subnet %(subnet)s netmask %(netmask)s {\n" \
458 " range %(dhcp_range)s;\n" \
459 "}" % server_conf,
460 self.local_servers))
461 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
Paul Stewart326badb2012-12-18 14:18:54 -0800462 (conf_file,
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700463 '\n'.join(('ddns-update-style none;', dhcp_conf))))
464 self.router.run("touch %s" % self.dhcpd_leases)
465
466 self.router.run("pkill dhcpd >/dev/null 2>&1", ignore_status=True)
467 self.router.run("%s -q -cf %s -lf %s" %
Paul Stewart326badb2012-12-18 14:18:54 -0800468 (self.cmd_dhcpd, conf_file, self.dhcpd_leases))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700469
470
Paul Stewart326badb2012-12-18 14:18:54 -0800471 def stop_dhcp_server(self, instance=None):
472 self._kill_process_instance('dhcpd', instance, 0)
473
Paul Stewart548cf452012-11-27 17:46:23 -0800474 def stop_dhcp_servers(self):
Paul Stewart326badb2012-12-18 14:18:54 -0800475 self.stop_dhcp_server(None)
Paul Stewart548cf452012-11-27 17:46:23 -0800476
477
Paul Stewartc2b3de82011-03-03 14:45:31 -0800478 def config(self, params):
479 if self.apmode:
480 self.hostap_config(params)
481 else:
482 self.station_config(params)
483
484
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700485 def get_wifi_ip(self, ap_num):
486 if self.local_servers:
487 return self.ip_addr(self.local_servers[ap_num]['netblock'],
488 'local')
489 else:
490 raise error.TestFail("No IP address assigned")
Paul Stewart5977da92011-06-01 19:14:08 -0700491
492
Paul Stewart17350be2012-12-14 13:34:54 -0800493 def get_hostapd_mac(self, ap_num):
494 instance = self.hostapd_instances[ap_num]
495 interface = instance['interface']
496 result = self.router.run('%s addr show %s' % (self.cmd_ip, interface))
497 # Example response:
498 # 1: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 UP qlen 1000
499 # link/ether 99:88:77:66:55:44 brd ff:ff:ff:ff:ff:ff
500 # inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
501 # inet6 fe80::6a7f:74ff:fe66:5544/64 scope link
502 # we want the MAC address after the "link/ether" above.
503 parts = result.stdout.split(' ')
504 return parts[parts.index('link/ether') + 1]
505
506
Christopher Wileyd89b5282013-04-10 15:21:26 -0700507 def deconfig(self, params={}):
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700508 """ De-configure the AP (will also bring wlan down) """
Sam Leffler6969d1d2010-03-15 16:07:11 -0700509
Paul Stewartc2b3de82011-03-03 14:45:31 -0800510 if not self.hostapd['configured'] and not self.station['configured']:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700511 return
Sam Leffler6969d1d2010-03-15 16:07:11 -0700512
Paul Stewartc2b3de82011-03-03 14:45:31 -0800513 if self.hostapd['configured']:
Paul Stewart326badb2012-12-18 14:18:54 -0800514 local_servers = []
Paul Stewart21737812012-12-06 11:03:32 -0800515 if 'instance' in params:
516 instances = [ self.hostapd_instances.pop(params['instance']) ]
Paul Stewart326badb2012-12-18 14:18:54 -0800517 for server in self.local_servers:
518 if server['interface'] == instances[0]['interface']:
519 local_servers = [server]
520 self.local_servers.remove(server)
521 break
Paul Stewart21737812012-12-06 11:03:32 -0800522 else:
523 instances = self.hostapd_instances
524 self.hostapd_instances = []
Paul Stewart326badb2012-12-18 14:18:54 -0800525 local_servers = self.local_servers
526 self.local_servers = []
Paul Stewart64cc4292011-06-01 10:59:36 -0700527
Paul Stewart21737812012-12-06 11:03:32 -0800528 for instance in instances:
529 if 'silent' in params:
530 # Deconfigure without notifying DUT. Remove the interface
531 # hostapd uses to send beacon and DEAUTH packets.
532 self._remove_interface(instance['interface'], True)
533
Paul Stewart326badb2012-12-18 14:18:54 -0800534 self.kill_hostapd_instance(instance['conf_file'])
Paul Stewart548cf452012-11-27 17:46:23 -0800535 self.router.get_file(instance['log_file'],
536 'debug/hostapd_router_%d_%s.log' %
537 (self.hostapd['log_count'],
538 instance['interface']))
539 self._release_wlanif(instance['interface'])
540# self.router.run("rm -f %(log_file)s %(conf_file)s" % instance)
Paul Stewartf854d2e2011-05-04 13:19:18 -0700541 self.hostapd['log_count'] += 1
Paul Stewartc2b3de82011-03-03 14:45:31 -0800542 if self.station['configured']:
Christopher Wiley05262d62013-04-17 17:53:59 -0700543 local_servers = self.local_servers
544 self.local_servers = []
Paul Stewartc2b3de82011-03-03 14:45:31 -0800545 if self.station['type'] == 'ibss':
546 self.router.run("%s dev %s ibss leave" %
547 (self.cmd_iw, self.station['interface']))
548 else:
549 self.router.run("%s dev %s disconnect" %
550 (self.cmd_iw, self.station['interface']))
551 self.router.run("%s link set %s down" % (self.cmd_ip,
552 self.station['interface']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700553
Paul Stewart326badb2012-12-18 14:18:54 -0800554 for server in local_servers:
555 self.stop_dhcp_server(server['interface'])
556 self.router.run("%s addr del %s" %
557 (self.cmd_ip, server['ip_params']),
558 ignore_status=True)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700559
560 self.hostapd['configured'] = False
Paul Stewartc2b3de82011-03-03 14:45:31 -0800561 self.station['configured'] = False
Paul Stewart7cb1f062010-06-10 15:46:20 -0700562
563
Paul Stewart17350be2012-12-14 13:34:54 -0800564 def verify_pmksa_auth(self, params):
565 instance_num = params.get('instance', 0)
566 instance = self.hostapd_instances[instance_num]
567 pmksa_match = 'PMK from PMKSA cache - skip IEEE 802.1X.EAP'
568 self.router.run('grep -q "%s" %s' % (pmksa_match, instance['log_file']))
569
570
Paul Stewart7cb1f062010-06-10 15:46:20 -0700571 def get_ssid(self):
572 return self.hostapd['conf']['ssid']
Paul Stewart98022e22010-10-22 10:33:14 -0700573
574
575 def set_txpower(self, params):
Paul Stewart548cf452012-11-27 17:46:23 -0800576 interface = params.get('interface',
577 self.hostapd_instances[0]['interface'])
578 power = params.get('power', 'auto')
Paul Stewart98022e22010-10-22 10:33:14 -0700579 self.router.run("%s dev %s set txpower %s" %
Paul Stewart548cf452012-11-27 17:46:23 -0800580 (self.cmd_iw, interface, power))
Paul Stewartaa52e8c2011-05-24 08:46:23 -0700581
582
583 def deauth(self, params):
584 self.router.run('%s -p%s deauthenticate %s' %
585 (self.cmd_hostapd_cli,
586 self.hostapd['conf']['ctrl_interface'],
587 params['client']))
mukesh agrawalfe0e85b2011-08-09 14:24:15 -0700588
589
590 def _pre_config_hook(self, config):
591 """
592 Hook for subclasses. Run after gathering configuration parameters,
593 but before writing parameters to config file.
594 """
595 pass
596
597
598 def _pre_start_hook(self, params):
599 """
600 Hook for subclasses. Run after generating hostapd config file, but
601 before starting hostapd.
602 """
603 pass
604
605
606 def _post_start_hook(self, params):
607 """Hook for subclasses. Run after starting hostapd."""
608 pass