1 # Test cases for VHT operations with hostapd
2 # Copyright (c) 2014, Qualcomm Atheros, Inc.
3 # Copyright (c) 2013, Intel Corporation
5 # This software may be distributed under the terms of the BSD license.
6 # See README for more details.
9 logger = logging.getLogger()
11 import subprocess, time
15 from utils import HwsimSkip
16 from test_dfs import wait_dfs_event
17 from test_ap_csa import csa_supported
18 from test_ap_ht import clear_scan_cache
21 cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
22 reg = cmd.stdout.read()
23 if "@ 80)" in reg or "@ 160)" in reg:
27 def test_ap_vht80(dev, apdev):
28 """VHT with 80 MHz channel width"""
31 params = { "ssid": "vht",
35 "ht_capab": "[HT40+]",
38 "vht_oper_chwidth": "1",
39 "vht_oper_centr_freq_seg0_idx": "42" }
40 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
41 bssid = apdev[0]['bssid']
43 dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
44 hwsim_utils.test_connectivity(dev[0], hapd)
45 sig = dev[0].request("SIGNAL_POLL").splitlines()
46 if "FREQUENCY=5180" not in sig:
47 raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
48 if "WIDTH=80 MHz" not in sig:
49 raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
50 est = dev[0].get_bss(bssid)['est_throughput']
52 raise Exception("Unexpected BSS est_throughput: " + est)
54 if isinstance(e, Exception) and str(e) == "AP startup failed":
55 if not vht_supported():
56 raise HwsimSkip("80 MHz channel not supported in regulatory information")
59 dev[0].request("DISCONNECT")
61 hapd.request("DISABLE")
62 subprocess.call(['iw', 'reg', 'set', '00'])
63 dev[0].flush_scan_cache()
65 def vht80_test(apdev, dev, channel, ht_capab):
66 clear_scan_cache(apdev['ifname'])
69 params = { "ssid": "vht",
72 "channel": str(channel),
76 "vht_oper_chwidth": "1",
77 "vht_oper_centr_freq_seg0_idx": "42" }
78 hapd = hostapd.add_ap(apdev['ifname'], params)
79 bssid = apdev['bssid']
81 dev.connect("vht", key_mgmt="NONE", scan_freq=str(5000 + 5 * channel))
82 hwsim_utils.test_connectivity(dev, hapd)
84 if isinstance(e, Exception) and str(e) == "AP startup failed":
85 if not vht_supported():
86 raise HwsimSkip("80 MHz channel not supported in regulatory information")
89 dev.request("DISCONNECT")
91 hapd.request("DISABLE")
92 subprocess.call(['iw', 'reg', 'set', '00'])
93 dev.flush_scan_cache()
95 def test_ap_vht80b(dev, apdev):
96 """VHT with 80 MHz channel width (HT40- channel 40)"""
97 vht80_test(apdev[0], dev[0], 40, "[HT40-]")
99 def test_ap_vht80c(dev, apdev):
100 """VHT with 80 MHz channel width (HT40+ channel 44)"""
101 vht80_test(apdev[0], dev[0], 44, "[HT40+]")
103 def test_ap_vht80d(dev, apdev):
104 """VHT with 80 MHz channel width (HT40- channel 48)"""
105 vht80_test(apdev[0], dev[0], 48, "[HT40-]")
107 def test_ap_vht80_params(dev, apdev):
108 """VHT with 80 MHz channel width and number of optional features enabled"""
111 params = { "ssid": "vht",
112 "country_code": "FI",
115 "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
118 "vht_oper_chwidth": "1",
119 "vht_capab": "[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP0]",
120 "vht_oper_centr_freq_seg0_idx": "42",
122 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
124 dev[1].connect("vht", key_mgmt="NONE", scan_freq="5180",
125 disable_vht="1", wait_connect=False)
126 dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
127 ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
129 raise Exception("Association rejection timed out")
130 if "status_code=104" not in ev:
131 raise Exception("Unexpected rejection status code")
132 dev[1].request("DISCONNECT")
133 hwsim_utils.test_connectivity(dev[0], hapd)
135 if isinstance(e, Exception) and str(e) == "AP startup failed":
136 if not vht_supported():
137 raise HwsimSkip("80 MHz channel not supported in regulatory information")
140 dev[0].request("DISCONNECT")
141 dev[1].request("DISCONNECT")
143 hapd.request("DISABLE")
144 subprocess.call(['iw', 'reg', 'set', '00'])
145 dev[0].flush_scan_cache()
146 dev[1].flush_scan_cache()
148 def test_ap_vht_20(devs, apdevs):
149 """VHT and 20 MHz channel"""
154 params = { "ssid": "test-vht20",
155 "country_code": "DE",
162 "vht_oper_chwidth": "0",
163 "vht_oper_centr_freq_seg0_idx": "0",
164 "supported_rates": "60 120 240 360 480 540",
167 hapd = hostapd.add_ap(ap['ifname'], params)
168 dev.connect("test-vht20", scan_freq="5180", key_mgmt="NONE")
169 hwsim_utils.test_connectivity(dev, hapd)
171 dev.request("DISCONNECT")
173 hapd.request("DISABLE")
174 subprocess.call(['iw', 'reg', 'set', '00'])
175 dev.flush_scan_cache()
177 def test_ap_vht_40(devs, apdevs):
178 """VHT and 40 MHz channel"""
183 params = { "ssid": "test-vht40",
184 "country_code": "DE",
189 "ht_capab": "[HT40+]",
191 "vht_oper_chwidth": "0",
192 "vht_oper_centr_freq_seg0_idx": "0",
194 hapd = hostapd.add_ap(ap['ifname'], params)
195 dev.connect("test-vht40", scan_freq="5180", key_mgmt="NONE")
196 hwsim_utils.test_connectivity(dev, hapd)
198 dev.request("DISCONNECT")
200 hapd.request("DISABLE")
201 subprocess.call(['iw', 'reg', 'set', '00'])
202 dev.flush_scan_cache()
204 def test_ap_vht_capab_not_supported(dev, apdev):
205 """VHT configuration with driver not supporting all vht_capab entries"""
207 params = { "ssid": "vht",
208 "country_code": "FI",
211 "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
214 "vht_oper_chwidth": "1",
215 "vht_capab": "[MAX-MPDU-7991][MAX-MPDU-11454][VHT160][VHT160-80PLUS80][RXLDPC][SHORT-GI-80][SHORT-GI-160][TX-STBC-2BY1][RX-STBC-1][RX-STBC-12][RX-STBC-123][RX-STBC-1234][SU-BEAMFORMER][SU-BEAMFORMEE][BF-ANTENNA-2][BF-ANTENNA-3][BF-ANTENNA-4][SOUNDING-DIMENSION-2][SOUNDING-DIMENSION-3][SOUNDING-DIMENSION-4][MU-BEAMFORMER][VHT-TXOP-PS][HTC-VHT][MAX-A-MPDU-LEN-EXP0][MAX-A-MPDU-LEN-EXP7][VHT-LINK-ADAPT2][VHT-LINK-ADAPT3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]",
216 "vht_oper_centr_freq_seg0_idx": "42",
218 hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
219 ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
221 raise Exception("Startup failure not reported")
222 for i in range(1, 7):
223 if "OK" not in hapd.request("SET vht_capab [MAX-A-MPDU-LEN-EXP%d]" % i):
224 raise Exception("Unexpected SET failure")
226 subprocess.call(['iw', 'reg', 'set', '00'])
228 def test_ap_vht160(dev, apdev):
229 """VHT with 160 MHz channel width"""
233 params = { "ssid": "vht",
234 "country_code": "FI",
237 "ht_capab": "[HT40+]",
240 "vht_oper_chwidth": "2",
241 "vht_oper_centr_freq_seg0_idx": "50",
244 hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
246 ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
247 if "DFS-CAC-START" not in ev:
248 raise Exception("Unexpected DFS event")
250 state = hapd.get_status_field("state")
252 if state == "DISABLED" and not os.path.exists("dfs"):
253 # Not all systems have recent enough CRDA version and
254 # wireless-regdb changes to support 160 MHz and DFS. For now,
255 # do not report failures for this test case.
256 raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
257 raise Exception("Unexpected interface state: " + state)
259 params = { "ssid": "vht2",
260 "country_code": "FI",
263 "ht_capab": "[HT40-]",
266 "vht_oper_chwidth": "2",
267 "vht_oper_centr_freq_seg0_idx": "114",
270 hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
272 ev = wait_dfs_event(hapd2, "DFS-CAC-START", 5)
273 if "DFS-CAC-START" not in ev:
274 raise Exception("Unexpected DFS event(2)")
276 state = hapd2.get_status_field("state")
278 raise Exception("Unexpected interface state(2): " + state)
280 logger.info("Waiting for CAC to complete")
282 ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
283 if "success=1" not in ev:
284 raise Exception("CAC failed")
285 if "freq=5180" not in ev:
286 raise Exception("Unexpected DFS freq result")
288 ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
290 raise Exception("AP setup timed out")
292 state = hapd.get_status_field("state")
293 if state != "ENABLED":
294 raise Exception("Unexpected interface state")
296 ev = wait_dfs_event(hapd2, "DFS-CAC-COMPLETED", 70)
297 if "success=1" not in ev:
298 raise Exception("CAC failed(2)")
299 if "freq=5520" not in ev:
300 raise Exception("Unexpected DFS freq result(2)")
302 ev = hapd2.wait_event(["AP-ENABLED"], timeout=5)
304 raise Exception("AP setup timed out(2)")
306 state = hapd2.get_status_field("state")
307 if state != "ENABLED":
308 raise Exception("Unexpected interface state(2)")
310 freq = hapd2.get_status_field("freq")
312 raise Exception("Unexpected frequency(2)")
314 dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
315 hwsim_utils.test_connectivity(dev[0], hapd)
316 sig = dev[0].request("SIGNAL_POLL").splitlines()
317 if "FREQUENCY=5180" not in sig:
318 raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
319 if "WIDTH=160 MHz" not in sig:
320 raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
321 dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5520")
322 hwsim_utils.test_connectivity(dev[1], hapd2)
323 sig = dev[1].request("SIGNAL_POLL").splitlines()
324 if "FREQUENCY=5520" not in sig:
325 raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
326 if "WIDTH=160 MHz" not in sig:
327 raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
329 if isinstance(e, Exception) and str(e) == "AP startup failed":
330 if not vht_supported():
331 raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
334 dev[0].request("DISCONNECT")
335 dev[1].request("DISCONNECT")
337 hapd.request("DISABLE")
339 hapd2.request("DISABLE")
340 subprocess.call(['iw', 'reg', 'set', '00'])
341 dev[0].flush_scan_cache()
342 dev[1].flush_scan_cache()
344 def test_ap_vht160_no_dfs(dev, apdev):
345 """VHT with 160 MHz channel width and no DFS"""
348 params = { "ssid": "vht",
349 "country_code": "ZA",
352 "ht_capab": "[HT40-]",
355 "vht_oper_chwidth": "2",
356 "vht_oper_centr_freq_seg0_idx": "114",
359 hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
360 ev = hapd.wait_event(["AP-ENABLED"], timeout=2)
362 cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
363 reg = cmd.stdout.readlines()
365 if "5490" in r and "DFS" in r:
366 raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
367 raise Exception("AP setup timed out")
369 dev[0].connect("vht", key_mgmt="NONE", scan_freq="5520")
370 hwsim_utils.test_connectivity(dev[0], hapd)
371 sig = dev[0].request("SIGNAL_POLL").splitlines()
372 if "FREQUENCY=5520" not in sig:
373 raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
374 if "WIDTH=160 MHz" not in sig:
375 raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
377 if isinstance(e, Exception) and str(e) == "AP startup failed":
378 if not vht_supported():
379 raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
382 dev[0].request("DISCONNECT")
384 hapd.request("DISABLE")
385 subprocess.call(['iw', 'reg', 'set', '00'])
386 dev[0].flush_scan_cache()
388 def test_ap_vht80plus80(dev, apdev):
389 """VHT with 80+80 MHz channel width"""
393 params = { "ssid": "vht",
394 "country_code": "US",
397 "ht_capab": "[HT40+]",
400 "vht_oper_chwidth": "3",
401 "vht_oper_centr_freq_seg0_idx": "58",
402 "vht_oper_centr_freq_seg1_idx": "155",
405 hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
406 # This will actually fail since DFS on 80+80 is not yet supported
407 ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
408 # ignore result to avoid breaking the test once 80+80 DFS gets enabled
410 params = { "ssid": "vht2",
411 "country_code": "US",
414 "ht_capab": "[HT40+]",
417 "vht_oper_chwidth": "3",
418 "vht_oper_centr_freq_seg0_idx": "42",
419 "vht_oper_centr_freq_seg1_idx": "155" }
420 hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
422 ev = hapd2.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
424 raise Exception("AP setup timed out(2)")
425 if "AP-DISABLED" in ev:
426 # Assume this failed due to missing regulatory update for now
427 raise HwsimSkip("80+80 MHz channel not supported in regulatory information")
429 state = hapd2.get_status_field("state")
430 if state != "ENABLED":
431 raise Exception("Unexpected interface state(2)")
433 dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5180")
434 hwsim_utils.test_connectivity(dev[1], hapd2)
435 sig = dev[1].request("SIGNAL_POLL").splitlines()
436 if "FREQUENCY=5180" not in sig:
437 raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
438 if "WIDTH=80+80 MHz" not in sig:
439 raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
440 if "CENTER_FRQ1=5210" not in sig:
441 raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
442 if "CENTER_FRQ2=5775" not in sig:
443 raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
445 if isinstance(e, Exception) and str(e) == "AP startup failed":
446 if not vht_supported():
447 raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
450 dev[0].request("DISCONNECT")
451 dev[1].request("DISCONNECT")
453 hapd.request("DISABLE")
455 hapd2.request("DISABLE")
456 subprocess.call(['iw', 'reg', 'set', '00'])
457 dev[0].flush_scan_cache()
458 dev[1].flush_scan_cache()
460 def test_ap_vht80_csa(dev, apdev):
461 """VHT with 80 MHz channel width and CSA"""
462 csa_supported(dev[0])
465 params = { "ssid": "vht",
466 "country_code": "US",
469 "ht_capab": "[HT40+]",
472 "vht_oper_chwidth": "1",
473 "vht_oper_centr_freq_seg0_idx": "155" }
474 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
476 dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
477 hwsim_utils.test_connectivity(dev[0], hapd)
479 hapd.request("CHAN_SWITCH 5 5180 ht vht blocktx center_freq1=5210 sec_channel_offset=1 bandwidth=80")
480 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
482 raise Exception("CSA finished event timed out")
483 if "freq=5180" not in ev:
484 raise Exception("Unexpected channel in CSA finished event")
486 hwsim_utils.test_connectivity(dev[0], hapd)
488 hapd.request("CHAN_SWITCH 5 5745")
489 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
491 raise Exception("CSA finished event timed out")
492 if "freq=5745" not in ev:
493 raise Exception("Unexpected channel in CSA finished event")
495 hwsim_utils.test_connectivity(dev[0], hapd)
497 # This CSA to same channel will fail in kernel, so use this only for
498 # extra code coverage.
499 hapd.request("CHAN_SWITCH 5 5745")
500 hapd.wait_event(["AP-CSA-FINISHED"], timeout=1)
502 if isinstance(e, Exception) and str(e) == "AP startup failed":
503 if not vht_supported():
504 raise HwsimSkip("80 MHz channel not supported in regulatory information")
507 dev[0].request("DISCONNECT")
509 hapd.request("DISABLE")
510 subprocess.call(['iw', 'reg', 'set', '00'])
511 dev[0].flush_scan_cache()
513 def test_ap_vht_on_24ghz(dev, apdev):
514 """Subset of VHT features on 2.4 GHz"""
516 params = { "ssid": "test-vht-2g",
521 "vht_capab": "[MAX-MPDU-11454]",
522 "vht_oper_chwidth": "0",
523 "vht_oper_centr_freq_seg0_idx": "1"
525 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
527 if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd1300904c0400bf0c3240820feaff0000eaff0000"):
528 raise Exception("Failed to add vendor element")
529 dev[0].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
530 hwsim_utils.test_connectivity(dev[0], hapd)
531 sta = hapd.get_sta(dev[0].own_addr())
532 if '[VENDOR_VHT]' not in sta['flags']:
533 raise Exception("No VENDOR_VHT STA flag")
535 dev[1].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
536 sta = hapd.get_sta(dev[1].own_addr())
537 if '[VENDOR_VHT]' in sta['flags']:
538 raise Exception("Unexpected VENDOR_VHT STA flag")
540 dev[0].request("VENDOR_ELEM_REMOVE 13 *")
542 def test_prefer_vht40(dev, apdev):
543 """Preference on VHT40 over HT40"""
547 params = { "ssid": "test",
548 "country_code": "FI",
552 "ht_capab": "[HT40+]" }
553 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
554 bssid = apdev[0]['bssid']
556 params = { "ssid": "test",
557 "country_code": "FI",
562 "ht_capab": "[HT40+]",
564 "vht_oper_chwidth": "0",
565 "vht_oper_centr_freq_seg0_idx": "0",
567 hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
568 bssid2 = apdev[1]['bssid']
570 dev[0].scan_for_bss(bssid, freq=5180)
571 dev[0].scan_for_bss(bssid2, freq=5180)
572 dev[0].connect("test", scan_freq="5180", key_mgmt="NONE")
573 if dev[0].get_status_field('bssid') != bssid2:
574 raise Exception("Unexpected BSS selected")
576 est = dev[0].get_bss(bssid)['est_throughput']
578 raise Exception("Unexpected BSS0 est_throughput: " + est)
580 est = dev[0].get_bss(bssid2)['est_throughput']
582 raise Exception("Unexpected BSS1 est_throughput: " + est)
584 dev[0].request("DISCONNECT")
586 hapd2.request("DISABLE")
587 subprocess.call(['iw', 'reg', 'set', '00'])
588 dev[0].flush_scan_cache()
590 def test_ap_vht80_pwr_constraint(dev, apdev):
591 """VHT with 80 MHz channel width and local power constraint"""
594 params = { "ssid": "vht",
595 "country_code": "FI",
598 "ht_capab": "[HT40+]",
600 "local_pwr_constraint": "3",
603 "vht_oper_chwidth": "1",
604 "vht_oper_centr_freq_seg0_idx": "42" }
605 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
607 dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
609 if isinstance(e, Exception) and str(e) == "AP startup failed":
610 if not vht_supported():
611 raise HwsimSkip("80 MHz channel not supported in regulatory information")
614 dev[0].request("DISCONNECT")
616 hapd.request("DISABLE")
617 subprocess.call(['iw', 'reg', 'set', '00'])
618 dev[0].flush_scan_cache()