1# Test cases for VHT operations with hostapd
2# Copyright (c) 2014, Qualcomm Atheros, Inc.
3# Copyright (c) 2013, Intel Corporation
4#
5# This software may be distributed under the terms of the BSD license.
6# See README for more details.
7
8import logging
9logger = logging.getLogger()
10import os
11import subprocess, time
12
13import hwsim_utils
14import hostapd
15from wpasupplicant import WpaSupplicant
16from utils import *
17from test_dfs import wait_dfs_event
18
19def test_ap_vht80(dev, apdev):
20    """VHT with 80 MHz channel width"""
21    clear_scan_cache(apdev[0])
22    try:
23        hapd = None
24        params = {"ssid": "vht",
25                  "country_code": "FI",
26                  "hw_mode": "a",
27                  "channel": "36",
28                  "ht_capab": "[HT40+]",
29                  "ieee80211n": "1",
30                  "ieee80211ac": "1",
31                  "vht_oper_chwidth": "1",
32                  "vht_oper_centr_freq_seg0_idx": "42"}
33        hapd = hostapd.add_ap(apdev[0], params)
34        bssid = apdev[0]['bssid']
35
36        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
37        hwsim_utils.test_connectivity(dev[0], hapd)
38        sig = dev[0].request("SIGNAL_POLL").splitlines()
39        if "FREQUENCY=5180" not in sig:
40            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
41        if "WIDTH=80 MHz" not in sig:
42            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
43        est = dev[0].get_bss(bssid)['est_throughput']
44        if est != "390001":
45            raise Exception("Unexpected BSS est_throughput: " + est)
46        status = dev[0].get_status()
47        if status["ieee80211ac"] != "1":
48            raise Exception("Unexpected STATUS ieee80211ac value (STA)")
49        status = hapd.get_status()
50        logger.info("hostapd STATUS: " + str(status))
51        if status["ieee80211n"] != "1":
52            raise Exception("Unexpected STATUS ieee80211n value")
53        if status["ieee80211ac"] != "1":
54            raise Exception("Unexpected STATUS ieee80211ac value")
55        if status["secondary_channel"] != "1":
56            raise Exception("Unexpected STATUS secondary_channel value")
57        if status["vht_oper_chwidth"] != "1":
58            raise Exception("Unexpected STATUS vht_oper_chwidth value")
59        if status["vht_oper_centr_freq_seg0_idx"] != "42":
60            raise Exception("Unexpected STATUS vht_oper_centr_freq_seg0_idx value")
61        if "vht_caps_info" not in status:
62            raise Exception("Missing vht_caps_info")
63
64        sta = hapd.get_sta(dev[0].own_addr())
65        logger.info("hostapd STA: " + str(sta))
66        if "[HT]" not in sta['flags']:
67            raise Exception("Missing STA flag: HT")
68        if "[VHT]" not in sta['flags']:
69            raise Exception("Missing STA flag: VHT")
70        if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2:
71            raise Exception("No Supported Operating Classes information for STA")
72        opclass = int(sta['supp_op_classes'][0:2], 16)
73        if opclass != 128:
74            raise Exception("Unexpected Current Operating Class from STA: %d" % opclass)
75    except Exception as e:
76        if isinstance(e, Exception) and str(e) == "AP startup failed":
77            if not vht_supported():
78                raise HwsimSkip("80 MHz channel not supported in regulatory information")
79        raise
80    finally:
81        dev[0].request("DISCONNECT")
82        clear_regdom(hapd, dev)
83
84def test_ap_vht_wifi_generation(dev, apdev):
85    """VHT and wifi_generation"""
86    clear_scan_cache(apdev[0])
87    try:
88        hapd = None
89        params = {"ssid": "vht",
90                  "country_code": "FI",
91                  "hw_mode": "a",
92                  "channel": "36",
93                  "ht_capab": "[HT40+]",
94                  "ieee80211n": "1",
95                  "ieee80211ac": "1",
96                  "vht_oper_chwidth": "1",
97                  "vht_oper_centr_freq_seg0_idx": "42"}
98        hapd = hostapd.add_ap(apdev[0], params)
99        bssid = apdev[0]['bssid']
100
101        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
102        status = dev[0].get_status()
103        if 'wifi_generation' not in status:
104            # For now, assume this is because of missing kernel support
105            raise HwsimSkip("Association Request IE reporting not supported")
106            #raise Exception("Missing wifi_generation information")
107        if status['wifi_generation'] != "5":
108            raise Exception("Unexpected wifi_generation value: " + status['wifi_generation'])
109
110        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
111        wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
112        wpas.connect("vht", key_mgmt="NONE", scan_freq="5180")
113        status = wpas.get_status()
114        if 'wifi_generation' not in status:
115            # For now, assume this is because of missing kernel support
116            raise HwsimSkip("Association Request IE reporting not supported")
117            #raise Exception("Missing wifi_generation information (connect)")
118        if status['wifi_generation'] != "5":
119            raise Exception("Unexpected wifi_generation value (connect): " + status['wifi_generation'])
120    except Exception as e:
121        if isinstance(e, Exception) and str(e) == "AP startup failed":
122            if not vht_supported():
123                raise HwsimSkip("80 MHz channel not supported in regulatory information")
124        raise
125    finally:
126        dev[0].request("DISCONNECT")
127        clear_regdom(hapd, dev)
128
129def vht80_test(apdev, dev, channel, ht_capab):
130    clear_scan_cache(apdev)
131    try:
132        hapd = None
133        params = {"ssid": "vht",
134                  "country_code": "FI",
135                  "hw_mode": "a",
136                  "channel": str(channel),
137                  "ht_capab": ht_capab,
138                  "ieee80211n": "1",
139                  "ieee80211ac": "1",
140                  "vht_oper_chwidth": "1",
141                  "vht_oper_centr_freq_seg0_idx": "42"}
142        hapd = hostapd.add_ap(apdev, params)
143        bssid = apdev['bssid']
144
145        dev[0].connect("vht", key_mgmt="NONE",
146                       scan_freq=str(5000 + 5 * channel))
147        hwsim_utils.test_connectivity(dev[0], hapd)
148    except Exception as e:
149        if isinstance(e, Exception) and str(e) == "AP startup failed":
150            if not vht_supported():
151                raise HwsimSkip("80 MHz channel not supported in regulatory information")
152        raise
153    finally:
154        clear_regdom(hapd, dev)
155
156def test_ap_vht80b(dev, apdev):
157    """VHT with 80 MHz channel width (HT40- channel 40)"""
158    vht80_test(apdev[0], dev, 40, "[HT40-]")
159
160def test_ap_vht80c(dev, apdev):
161    """VHT with 80 MHz channel width (HT40+ channel 44)"""
162    vht80_test(apdev[0], dev, 44, "[HT40+]")
163
164def test_ap_vht80d(dev, apdev):
165    """VHT with 80 MHz channel width (HT40- channel 48)"""
166    vht80_test(apdev[0], dev, 48, "[HT40-]")
167
168def test_ap_vht80e(dev, apdev):
169    """VHT with 80 MHz channel width (HT40- channel 161)"""
170    clear_scan_cache(apdev[0])
171    try:
172        hapd = None
173        params = {"ssid": "vht",
174                  "country_code": "US",
175                  "hw_mode": "a",
176                  "channel": "161",
177                  "ht_capab": "[HT40-]",
178                  "ieee80211n": "1",
179                  "ieee80211ac": "1",
180                  "vht_oper_chwidth": "1",
181                  "vht_oper_centr_freq_seg0_idx": "155"}
182        hapd = hostapd.add_ap(apdev[0], params)
183        bssid = apdev[0]['bssid']
184
185        dev[0].connect("vht", key_mgmt="NONE",
186                       scan_freq=str(5000 + 5 * 161))
187        hwsim_utils.test_connectivity(dev[0], hapd)
188    except Exception as e:
189        if isinstance(e, Exception) and str(e) == "AP startup failed":
190            if not vht_supported():
191                raise HwsimSkip("80 MHz channel not supported in regulatory information")
192        raise
193    finally:
194        clear_regdom(hapd, dev)
195
196def test_ap_vht80_params(dev, apdev):
197    """VHT with 80 MHz channel width and number of optional features enabled"""
198    clear_scan_cache(apdev[0])
199    try:
200        hapd = None
201        params = {"ssid": "vht",
202                  "country_code": "FI",
203                  "hw_mode": "a",
204                  "channel": "36",
205                  "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
206                  "ieee80211n": "1",
207                  "ieee80211ac": "1",
208                  "vht_oper_chwidth": "1",
209                  "vht_capab": "[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP0]",
210                  "vht_oper_centr_freq_seg0_idx": "42",
211                  "require_vht": "1"}
212        hapd = hostapd.add_ap(apdev[0], params)
213
214        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
215        wpas.interface_add("wlan5",
216                           drv_params="extra_bss_membership_selectors=126")
217
218        wpas.connect("vht", key_mgmt="NONE", scan_freq="5180",
219                     disable_vht="1", wait_connect=False)
220        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
221        dev[2].connect("vht", key_mgmt="NONE", scan_freq="5180",
222                       disable_sgi="1")
223        ev = wpas.wait_event(["CTRL-EVENT-ASSOC-REJECT"])
224        if ev is None:
225            raise Exception("Association rejection timed out")
226        if "status_code=104" not in ev:
227            raise Exception("Unexpected rejection status code")
228        wpas.request("DISCONNECT")
229        hwsim_utils.test_connectivity(dev[0], hapd)
230        sta0 = hapd.get_sta(dev[0].own_addr())
231        sta2 = hapd.get_sta(dev[2].own_addr())
232        capab0 = int(sta0['vht_caps_info'], base=16)
233        capab2 = int(sta2['vht_caps_info'], base=16)
234        if capab0 & 0x60 == 0:
235            raise Exception("dev[0] did not support SGI")
236        if capab2 & 0x60 != 0:
237            raise Exception("dev[2] claimed support for SGI")
238    except Exception as e:
239        if isinstance(e, Exception) and str(e) == "AP startup failed":
240            if not vht_supported():
241                raise HwsimSkip("80 MHz channel not supported in regulatory information")
242        raise
243    finally:
244        clear_regdom(hapd, dev, count=3)
245
246def test_ap_vht80_invalid(dev, apdev):
247    """VHT with invalid 80 MHz channel configuration (seg1)"""
248    try:
249        hapd = None
250        params = {"ssid": "vht",
251                  "country_code": "US",
252                  "hw_mode": "a",
253                  "channel": "36",
254                  "ht_capab": "[HT40+]",
255                  "ieee80211n": "1",
256                  "ieee80211ac": "1",
257                  "vht_oper_chwidth": "1",
258                  "vht_oper_centr_freq_seg0_idx": "42",
259                  "vht_oper_centr_freq_seg1_idx": "155",
260                  'ieee80211d': '1',
261                  'ieee80211h': '1'}
262        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
263        # This fails due to unexpected seg1 configuration
264        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
265        if ev is None:
266            raise Exception("AP-DISABLED not reported")
267    except Exception as e:
268        if isinstance(e, Exception) and str(e) == "AP startup failed":
269            if not vht_supported():
270                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
271        raise
272    finally:
273        clear_regdom(hapd, dev)
274
275def test_ap_vht80_invalid2(dev, apdev):
276    """VHT with invalid 80 MHz channel configuration (seg0)"""
277    try:
278        hapd = None
279        params = {"ssid": "vht",
280                  "country_code": "US",
281                  "hw_mode": "a",
282                  "channel": "36",
283                  "ht_capab": "[HT40+]",
284                  "ieee80211n": "1",
285                  "ieee80211ac": "1",
286                  "vht_oper_chwidth": "1",
287                  "vht_oper_centr_freq_seg0_idx": "46",
288                  'ieee80211d': '1',
289                  'ieee80211h': '1'}
290        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
291        # This fails due to invalid seg0 configuration
292        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
293        if ev is None:
294            raise Exception("AP-DISABLED not reported")
295    except Exception as e:
296        if isinstance(e, Exception) and str(e) == "AP startup failed":
297            if not vht_supported():
298                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
299        raise
300    finally:
301        clear_regdom(hapd, dev)
302
303def test_ap_vht_20(devs, apdevs):
304    """VHT and 20 MHz channel"""
305    dev = devs[0]
306    ap = apdevs[0]
307    try:
308        hapd = None
309        params = {"ssid": "test-vht20",
310                  "country_code": "DE",
311                  "hw_mode": "a",
312                  "channel": "36",
313                  "ieee80211n": "1",
314                  "ieee80211ac": "1",
315                  "ht_capab": "",
316                  "vht_capab": "",
317                  "vht_oper_chwidth": "0",
318                  "vht_oper_centr_freq_seg0_idx": "0",
319                  "supported_rates": "60 120 240 360 480 540",
320                  "require_vht": "1"}
321        hapd = hostapd.add_ap(ap, params)
322        dev.connect("test-vht20", scan_freq="5180", key_mgmt="NONE")
323        hwsim_utils.test_connectivity(dev, hapd)
324
325        sta = hapd.get_sta(dev.own_addr())
326        if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2:
327            raise Exception("No Supported Operating Classes information for STA")
328        opclass = int(sta['supp_op_classes'][0:2], 16)
329        if opclass != 115:
330            raise Exception("Unexpected Current Operating Class from STA: %d" % opclass)
331    finally:
332        dev.request("DISCONNECT")
333        clear_regdom(hapd, devs)
334
335def test_ap_vht_40(devs, apdevs):
336    """VHT and 40 MHz channel"""
337    dev = devs[0]
338    ap = apdevs[0]
339    clear_scan_cache(ap)
340    try:
341        hapd = None
342        params = {"ssid": "test-vht40",
343                  "country_code": "DE",
344                  "hw_mode": "a",
345                  "channel": "36",
346                  "ieee80211n": "1",
347                  "ieee80211ac": "1",
348                  "ht_capab": "[HT40+]",
349                  "vht_capab": "",
350                  "vht_oper_chwidth": "0",
351                  "vht_oper_centr_freq_seg0_idx": "0"}
352        hapd = hostapd.add_ap(ap, params)
353        dev.connect("test-vht40", scan_freq="5180", key_mgmt="NONE")
354        time.sleep(0.1)
355        hwsim_utils.test_connectivity(dev, hapd)
356
357        sta = hapd.get_sta(dev.own_addr())
358        if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2:
359            raise Exception("No Supported Operating Classes information for STA")
360        opclass = int(sta['supp_op_classes'][0:2], 16)
361        if opclass != 116:
362            raise Exception("Unexpected Current Operating Class from STA: %d" % opclass)
363    finally:
364        dev.request("DISCONNECT")
365        clear_regdom(hapd, devs)
366
367def test_ap_vht_capab_not_supported(dev, apdev):
368    """VHT configuration with driver not supporting all vht_capab entries"""
369    try:
370        hapd = None
371        params = {"ssid": "vht",
372                  "country_code": "FI",
373                  "hw_mode": "a",
374                  "channel": "36",
375                  "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
376                  "ieee80211n": "1",
377                  "ieee80211ac": "1",
378                  "vht_oper_chwidth": "1",
379                  "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]",
380                  "vht_oper_centr_freq_seg0_idx": "42",
381                  "require_vht": "1"}
382        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
383        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
384        if ev is None:
385            raise Exception("Startup failure not reported")
386        for i in range(1, 7):
387            if "OK" not in hapd.request("SET vht_capab [MAX-A-MPDU-LEN-EXP%d]" % i):
388                raise Exception("Unexpected SET failure")
389    finally:
390        clear_regdom(hapd, dev)
391
392def test_ap_vht160(dev, apdev):
393    """VHT with 160 MHz channel width (1)"""
394    clear_scan_cache(apdev[0])
395    try:
396        hapd = None
397        params = {"ssid": "vht",
398                  "country_code": "FI",
399                  "hw_mode": "a",
400                  "channel": "36",
401                  "ht_capab": "[HT40+]",
402                  "vht_capab": "[VHT160]",
403                  "ieee80211n": "1",
404                  "ieee80211ac": "1",
405                  "vht_oper_chwidth": "2",
406                  "vht_oper_centr_freq_seg0_idx": "50",
407                  'ieee80211d': '1',
408                  'ieee80211h': '1'}
409        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
410        bssid = apdev[0]['bssid']
411
412        ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
413        if "DFS-CAC-START" not in ev:
414            raise Exception("Unexpected DFS event")
415
416        state = hapd.get_status_field("state")
417        if state != "DFS":
418            if state == "DISABLED" and not os.path.exists("dfs"):
419                # Not all systems have recent enough CRDA version and
420                # wireless-regdb changes to support 160 MHz and DFS. For now,
421                # do not report failures for this test case.
422                raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
423            raise Exception("Unexpected interface state: " + state)
424
425        logger.info("Waiting for CAC to complete")
426
427        ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
428        if "success=1" not in ev:
429            raise Exception("CAC failed")
430        if "freq=5180" not in ev:
431            raise Exception("Unexpected DFS freq result")
432
433        ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
434        if not ev:
435            raise Exception("AP setup timed out")
436
437        state = hapd.get_status_field("state")
438        if state != "ENABLED":
439            raise Exception("Unexpected interface state")
440
441        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
442        dev[0].wait_regdom(country_ie=True)
443        hwsim_utils.test_connectivity(dev[0], hapd)
444        sig = dev[0].request("SIGNAL_POLL").splitlines()
445        if "FREQUENCY=5180" not in sig:
446            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
447        if "WIDTH=160 MHz" not in sig:
448            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
449
450        est = dev[0].get_bss(bssid)['est_throughput']
451        if est != "780001":
452            raise Exception("Unexpected BSS est_throughput: " + est)
453
454        sta = hapd.get_sta(dev[0].own_addr())
455        if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2:
456            raise Exception("No Supported Operating Classes information for STA")
457        opclass = int(sta['supp_op_classes'][0:2], 16)
458        if opclass != 129:
459            raise Exception("Unexpected Current Operating Class from STA: %d" % opclass)
460    except Exception as e:
461        if isinstance(e, Exception) and str(e) == "AP startup failed":
462            if not vht_supported():
463                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
464        raise
465    finally:
466        if hapd:
467            hapd.request("DISABLE")
468        dev[0].disconnect_and_stop_scan()
469        subprocess.call(['iw', 'reg', 'set', '00'])
470        dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
471        dev[0].flush_scan_cache()
472
473def test_ap_vht160b(dev, apdev):
474    """VHT with 160 MHz channel width (2)"""
475    try:
476        hapd = None
477
478        params = {"ssid": "vht",
479                  "country_code": "FI",
480                  "hw_mode": "a",
481                  "channel": "104",
482                  "ht_capab": "[HT40-]",
483                  "vht_capab": "[VHT160]",
484                  "ieee80211n": "1",
485                  "ieee80211ac": "1",
486                  "vht_oper_chwidth": "2",
487                  "vht_oper_centr_freq_seg0_idx": "114",
488                  'ieee80211d': '1',
489                  'ieee80211h': '1'}
490        hapd = hostapd.add_ap(apdev[1], params, wait_enabled=False)
491
492        ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
493        if "DFS-CAC-START" not in ev:
494            raise Exception("Unexpected DFS event(2)")
495
496        state = hapd.get_status_field("state")
497        if state != "DFS":
498            if state == "DISABLED" and not os.path.exists("dfs"):
499                # Not all systems have recent enough CRDA version and
500                # wireless-regdb changes to support 160 MHz and DFS. For now,
501                # do not report failures for this test case.
502                raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
503            raise Exception("Unexpected interface state: " + state)
504
505        logger.info("Waiting for CAC to complete")
506
507        ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
508        if "success=1" not in ev:
509            raise Exception("CAC failed(2)")
510        if "freq=5520" not in ev:
511            raise Exception("Unexpected DFS freq result(2)")
512
513        ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
514        if not ev:
515            raise Exception("AP setup timed out(2)")
516
517        state = hapd.get_status_field("state")
518        if state != "ENABLED":
519            raise Exception("Unexpected interface state(2)")
520
521        freq = hapd.get_status_field("freq")
522        if freq != "5520":
523            raise Exception("Unexpected frequency(2)")
524
525        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5520")
526        dev[0].wait_regdom(country_ie=True)
527        hwsim_utils.test_connectivity(dev[0], hapd)
528        sig = dev[0].request("SIGNAL_POLL").splitlines()
529        if "FREQUENCY=5520" not in sig:
530            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
531        if "WIDTH=160 MHz" not in sig:
532            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
533    except Exception as e:
534        if isinstance(e, Exception) and str(e) == "AP startup failed":
535            if not vht_supported():
536                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
537        raise
538    finally:
539        if hapd:
540            hapd.request("DISABLE")
541        dev[0].disconnect_and_stop_scan()
542        subprocess.call(['iw', 'reg', 'set', '00'])
543        dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
544        dev[0].flush_scan_cache()
545
546def test_ap_vht160_no_dfs_100_plus(dev, apdev):
547    """VHT with 160 MHz channel width and no DFS (100 plus)"""
548    run_ap_vht160_no_dfs(dev, apdev, "100", "[HT40+]")
549
550def test_ap_vht160_no_dfs(dev, apdev):
551    """VHT with 160 MHz channel width and no DFS (104 minus)"""
552    run_ap_vht160_no_dfs(dev, apdev, "104", "[HT40-]")
553
554def test_ap_vht160_no_dfs_108_plus(dev, apdev):
555    """VHT with 160 MHz channel width and no DFS (108 plus)"""
556    run_ap_vht160_no_dfs(dev, apdev, "108", "[HT40+]")
557
558def test_ap_vht160_no_dfs_112_minus(dev, apdev):
559    """VHT with 160 MHz channel width and no DFS (112 minus)"""
560    run_ap_vht160_no_dfs(dev, apdev, "112", "[HT40-]")
561
562def test_ap_vht160_no_dfs_116_plus(dev, apdev):
563    """VHT with 160 MHz channel width and no DFS (116 plus)"""
564    run_ap_vht160_no_dfs(dev, apdev, "116", "[HT40+]")
565
566def test_ap_vht160_no_dfs_120_minus(dev, apdev):
567    """VHT with 160 MHz channel width and no DFS (120 minus)"""
568    run_ap_vht160_no_dfs(dev, apdev, "120", "[HT40-]")
569
570def test_ap_vht160_no_dfs_124_plus(dev, apdev):
571    """VHT with 160 MHz channel width and no DFS (124 plus)"""
572    run_ap_vht160_no_dfs(dev, apdev, "124", "[HT40+]")
573
574def test_ap_vht160_no_dfs_128_minus(dev, apdev):
575    """VHT with 160 MHz channel width and no DFS (128 minus)"""
576    run_ap_vht160_no_dfs(dev, apdev, "128", "[HT40-]")
577
578def run_ap_vht160_no_dfs(dev, apdev, channel, ht_capab):
579    try:
580        hapd = None
581        params = {"ssid": "vht",
582                  "country_code": "ZA",
583                  "hw_mode": "a",
584                  "channel": channel,
585                  "ht_capab": ht_capab,
586                  "vht_capab": "[VHT160]",
587                  "ieee80211n": "1",
588                  "ieee80211ac": "1",
589                  "vht_oper_chwidth": "2",
590                  "vht_oper_centr_freq_seg0_idx": "114",
591                  'ieee80211d': '1',
592                  'ieee80211h': '1'}
593        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
594        ev = hapd.wait_event(["AP-ENABLED"], timeout=2)
595        if not ev:
596            cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
597            out, err = cmd.communicate()
598            reg = out.splitlines()
599            for r in reg:
600                if b"5490" in r and b"DFS" in r:
601                    raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
602            raise Exception("AP setup timed out")
603
604        freq = str(int(channel) * 5 + 5000)
605        dev[0].connect("vht", key_mgmt="NONE", scan_freq=freq)
606        dev[0].wait_regdom(country_ie=True)
607        hwsim_utils.test_connectivity(dev[0], hapd)
608        sig = dev[0].request("SIGNAL_POLL").splitlines()
609        if "FREQUENCY=" + freq not in sig:
610            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
611        if "WIDTH=160 MHz" not in sig:
612            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
613    except Exception as e:
614        if isinstance(e, Exception) and str(e) == "AP startup failed":
615            if not vht_supported():
616                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
617        raise
618    finally:
619        clear_regdom(hapd, dev)
620
621def test_ap_vht160_no_ht40(dev, apdev):
622    """VHT with 160 MHz channel width and HT40 disabled"""
623    try:
624        hapd = None
625        params = {"ssid": "vht",
626                  "country_code": "ZA",
627                  "hw_mode": "a",
628                  "channel": "108",
629                  "ht_capab": "",
630                  "ieee80211n": "1",
631                  "ieee80211ac": "1",
632                  "vht_oper_chwidth": "2",
633                  "vht_oper_centr_freq_seg0_idx": "114",
634                  'ieee80211d': '1',
635                  'ieee80211h': '1'}
636        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
637        ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=2)
638        if not ev:
639            cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
640            out, err = cmd.communicate()
641            reg = out.splitlines()
642            for r in reg:
643                if "5490" in r and "DFS" in r:
644                    raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
645            raise Exception("AP setup timed out")
646        if "AP-ENABLED" in ev:
647            # This was supposed to fail due to sec_channel_offset == 0
648            raise Exception("Unexpected AP-ENABLED")
649    except Exception as e:
650        if isinstance(e, Exception) and str(e) == "AP startup failed":
651            if not vht_supported():
652                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
653        raise
654    finally:
655        clear_regdom(hapd, dev)
656
657def test_ap_vht80plus80(dev, apdev):
658    """VHT with 80+80 MHz channel width"""
659    try:
660        hapd = None
661        hapd2 = None
662        params = {"ssid": "vht",
663                  "country_code": "US",
664                  "hw_mode": "a",
665                  "channel": "52",
666                  "ht_capab": "[HT40+]",
667                  "vht_capab": "[VHT160-80PLUS80]",
668                  "ieee80211n": "1",
669                  "ieee80211ac": "1",
670                  "vht_oper_chwidth": "3",
671                  "vht_oper_centr_freq_seg0_idx": "58",
672                  "vht_oper_centr_freq_seg1_idx": "155",
673                  'ieee80211d': '1',
674                  'ieee80211h': '1'}
675        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
676        # This will actually fail since DFS on 80+80 is not yet supported
677        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
678        # ignore result to avoid breaking the test once 80+80 DFS gets enabled
679
680        params = {"ssid": "vht2",
681                  "country_code": "US",
682                  "hw_mode": "a",
683                  "channel": "36",
684                  "ht_capab": "[HT40+]",
685                  "vht_capab": "[VHT160-80PLUS80]",
686                  "ieee80211n": "1",
687                  "ieee80211ac": "1",
688                  "vht_oper_chwidth": "3",
689                  "vht_oper_centr_freq_seg0_idx": "42",
690                  "vht_oper_centr_freq_seg1_idx": "155"}
691        hapd2 = hostapd.add_ap(apdev[1], params, wait_enabled=False)
692
693        ev = hapd2.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
694        if not ev:
695            raise Exception("AP setup timed out(2)")
696        if "AP-DISABLED" in ev:
697            # Assume this failed due to missing regulatory update for now
698            raise HwsimSkip("80+80 MHz channel not supported in regulatory information")
699
700        state = hapd2.get_status_field("state")
701        if state != "ENABLED":
702            raise Exception("Unexpected interface state(2)")
703
704        dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5180")
705        hwsim_utils.test_connectivity(dev[1], hapd2)
706        sig = dev[1].request("SIGNAL_POLL").splitlines()
707        if "FREQUENCY=5180" not in sig:
708            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
709        if "WIDTH=80+80 MHz" not in sig:
710            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
711        if "CENTER_FRQ1=5210" not in sig:
712            raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
713        if "CENTER_FRQ2=5775" not in sig:
714            raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
715
716        sta = hapd2.get_sta(dev[1].own_addr())
717        if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2:
718            raise Exception("No Supported Operating Classes information for STA")
719        opclass = int(sta['supp_op_classes'][0:2], 16)
720        if opclass != 130:
721            raise Exception("Unexpected Current Operating Class from STA: %d" % opclass)
722    except Exception as e:
723        if isinstance(e, Exception) and str(e) == "AP startup failed":
724            if not vht_supported():
725                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
726        raise
727    finally:
728        dev[0].request("DISCONNECT")
729        dev[1].request("DISCONNECT")
730        if hapd:
731            hapd.request("DISABLE")
732        if hapd2:
733            hapd2.request("DISABLE")
734        subprocess.call(['iw', 'reg', 'set', '00'])
735        dev[0].flush_scan_cache()
736        dev[1].flush_scan_cache()
737
738def test_ap_vht80plus80_invalid(dev, apdev):
739    """VHT with invalid 80+80 MHz channel"""
740    try:
741        hapd = None
742        params = {"ssid": "vht",
743                  "country_code": "US",
744                  "hw_mode": "a",
745                  "channel": "36",
746                  "ht_capab": "[HT40+]",
747                  "ieee80211n": "1",
748                  "ieee80211ac": "1",
749                  "vht_oper_chwidth": "3",
750                  "vht_oper_centr_freq_seg0_idx": "42",
751                  "vht_oper_centr_freq_seg1_idx": "0",
752                  'ieee80211d': '1',
753                  'ieee80211h': '1'}
754        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
755        # This fails due to missing(invalid) seg1 configuration
756        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
757        if ev is None:
758            raise Exception("AP-DISABLED not reported")
759    except Exception as e:
760        if isinstance(e, Exception) and str(e) == "AP startup failed":
761            if not vht_supported():
762                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
763        raise
764    finally:
765        clear_regdom(hapd, dev)
766
767def test_ap_vht80_csa(dev, apdev):
768    """VHT with 80 MHz channel width and CSA"""
769    csa_supported(dev[0])
770    try:
771        hapd = None
772        params = {"ssid": "vht",
773                  "country_code": "US",
774                  "hw_mode": "a",
775                  "channel": "149",
776                  "ht_capab": "[HT40+]",
777                  "ieee80211n": "1",
778                  "ieee80211ac": "1",
779                  "vht_oper_chwidth": "1",
780                  "vht_oper_centr_freq_seg0_idx": "155"}
781        hapd = hostapd.add_ap(apdev[0], params)
782
783        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
784        hwsim_utils.test_connectivity(dev[0], hapd)
785
786        hapd.request("CHAN_SWITCH 5 5180 ht vht blocktx center_freq1=5210 sec_channel_offset=1 bandwidth=80")
787        ev = hapd.wait_event(["CTRL-EVENT-STARTED-CHANNEL-SWITCH"], timeout=10)
788        if ev is None:
789            raise Exception("Channel switch start event not seen")
790        if "freq=5180" not in ev:
791            raise Exception("Unexpected channel in CS started")
792        ev = hapd.wait_event(["CTRL-EVENT-CHANNEL-SWITCH"], timeout=10)
793        if ev is None:
794            raise Exception("Channel switch completion event not seen")
795        if "freq=5180" not in ev:
796            raise Exception("Unexpected channel in CS completed")
797        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
798        if ev is None:
799            raise Exception("CSA finished event timed out")
800        if "freq=5180" not in ev:
801            raise Exception("Unexpected channel in CSA finished event")
802        time.sleep(0.5)
803        hwsim_utils.test_connectivity(dev[0], hapd)
804
805        hapd.request("CHAN_SWITCH 5 5745")
806        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
807        if ev is None:
808            raise Exception("CSA finished event timed out")
809        if "freq=5745" not in ev:
810            raise Exception("Unexpected channel in CSA finished event")
811        time.sleep(0.5)
812        hwsim_utils.test_connectivity(dev[0], hapd)
813
814        # This CSA to same channel will fail in kernel, so use this only for
815        # extra code coverage.
816        hapd.request("CHAN_SWITCH 5 5745")
817        hapd.wait_event(["AP-CSA-FINISHED"], timeout=1)
818    except Exception as e:
819        if isinstance(e, Exception) and str(e) == "AP startup failed":
820            if not vht_supported():
821                raise HwsimSkip("80 MHz channel not supported in regulatory information")
822        raise
823    finally:
824        dev[0].request("DISCONNECT")
825        clear_regdom(hapd, dev)
826
827def test_ap_vht_csa_vht80p80(dev, apdev):
828    """VHT CSA with VHT80+80 getting enabled"""
829    csa_supported(dev[0])
830    try:
831        hapd = None
832        params = {"ssid": "vht",
833                  "country_code": "US",
834                  "hw_mode": "a",
835                  "channel": "149",
836                  "ht_capab": "[HT40+]",
837                  "ieee80211n": "1",
838                  "ieee80211ac": "0"}
839        hapd = hostapd.add_ap(apdev[0], params)
840        bssid = hapd.own_addr()
841
842        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
843        hwsim_utils.test_connectivity(dev[0], hapd)
844
845        #if "OK" not in hapd.request("CHAN_SWITCH 5 5765 sec_channel_offset=-1 center_freq1=5775 center_freq2=5210 bandwidth=80 vht"):
846        if "OK" not in hapd.request("CHAN_SWITCH 5 5180 sec_channel_offset=1 center_freq1=5210 center_freq2=5775 bandwidth=80 vht"):
847            raise Exception("CHAN_SWITCH command failed")
848        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
849        if ev is None:
850            raise Exception("CSA finished event timed out")
851        if "freq=5180" not in ev:
852            raise Exception("Unexpected channel in CSA finished event")
853        ev = dev[0].wait_event(["CTRL-EVENT-CHANNEL-SWITCH"], timeout=5)
854        if ev is None:
855            raise Exception("Channel switch event not seen")
856        if "freq=5180" not in ev:
857            raise Exception("Channel mismatch: " + ev)
858        ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
859        if ev is not None:
860            raise Exception("Unexpected disconnection event from station")
861        hwsim_utils.test_connectivity(dev[0], hapd)
862
863        dev[1].connect("vht", key_mgmt="NONE", scan_freq="5180")
864        hwsim_utils.test_connectivity(dev[1], hapd)
865
866        if dev[1].get_status_field("ieee80211ac") != '1':
867            raise Exception("VHT not enabled as part of channel switch")
868        sig = dev[1].request("SIGNAL_POLL").splitlines()
869        logger.info("SIGNAL_POLL(1): " + str(sig))
870        if "FREQUENCY=5180" not in sig:
871            raise Exception("Correct FREQUENCY missing from SIGNAL_POLL")
872        if "WIDTH=80+80 MHz" not in sig:
873            raise Exception("Correct WIDTH missing from SIGNAL_POLL")
874        if "CENTER_FRQ1=5210" not in sig:
875            raise Exception("Correct CENTER_FRQ1 missing from SIGNAL_POLL")
876        if "CENTER_FRQ2=5775" not in sig:
877            raise Exception("Correct CENTER_FRQ1 missing from SIGNAL_POLL")
878
879        sig = dev[0].request("SIGNAL_POLL").splitlines()
880        logger.info("SIGNAL_POLL(0): " + str(sig))
881    finally:
882        dev[0].request("DISCONNECT")
883        dev[1].request("DISCONNECT")
884        if hapd:
885            hapd.request("DISABLE")
886        subprocess.call(['iw', 'reg', 'set', '00'])
887        dev[0].flush_scan_cache()
888        dev[1].flush_scan_cache()
889
890def test_ap_vht_csa_vht40(dev, apdev):
891    """VHT CSA with VHT40 getting enabled"""
892    csa_supported(dev[0])
893    try:
894        hapd = None
895        params = {"ssid": "vht",
896                  "country_code": "US",
897                  "hw_mode": "a",
898                  "channel": "149",
899                  "ht_capab": "[HT40+]",
900                  "ieee80211n": "1",
901                  "ieee80211ac": "0"}
902        hapd = hostapd.add_ap(apdev[0], params)
903        bssid = hapd.own_addr()
904
905        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
906        hwsim_utils.test_connectivity(dev[0], hapd)
907
908        hapd.request("CHAN_SWITCH 5 5765 sec_channel_offset=-1 center_freq1=5755 bandwidth=40 vht")
909        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
910        if ev is None:
911            raise Exception("CSA finished event timed out")
912        if "freq=5765" not in ev:
913            raise Exception("Unexpected channel in CSA finished event")
914        ev = dev[0].wait_event(["CTRL-EVENT-CHANNEL-SWITCH"], timeout=5)
915        if ev is None:
916            raise Exception("Channel switch event not seen")
917        if "freq=5765" not in ev:
918            raise Exception("Channel mismatch: " + ev)
919        ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
920        if ev is not None:
921            raise Exception("Unexpected disconnection event from station")
922        hwsim_utils.test_connectivity(dev[0], hapd)
923
924        dev[1].connect("vht", key_mgmt="NONE", scan_freq="5765")
925        hwsim_utils.test_connectivity(dev[1], hapd)
926
927        if dev[1].get_status_field("ieee80211ac") != '1':
928            raise Exception("VHT not enabled as part of channel switch")
929    finally:
930        dev[0].request("DISCONNECT")
931        dev[1].request("DISCONNECT")
932        if hapd:
933            hapd.request("DISABLE")
934        subprocess.call(['iw', 'reg', 'set', '00'])
935        dev[0].flush_scan_cache()
936        dev[1].flush_scan_cache()
937
938def test_ap_vht_csa_vht20(dev, apdev):
939    """VHT CSA with VHT20 getting enabled"""
940    csa_supported(dev[0])
941    try:
942        hapd = None
943        params = {"ssid": "vht",
944                  "country_code": "US",
945                  "hw_mode": "a",
946                  "channel": "149",
947                  "ht_capab": "[HT40+]",
948                  "ieee80211n": "1",
949                  "ieee80211ac": "0"}
950        hapd = hostapd.add_ap(apdev[0], params)
951        bssid = hapd.own_addr()
952
953        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
954        hwsim_utils.test_connectivity(dev[0], hapd)
955
956        hapd.request("CHAN_SWITCH 5 5200 center_freq1=5200 bandwidth=20 vht")
957        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
958        if ev is None:
959            raise Exception("CSA finished event timed out")
960        if "freq=5200" not in ev:
961            raise Exception("Unexpected channel in CSA finished event")
962        time.sleep(0.5)
963        hwsim_utils.test_connectivity(dev[0], hapd)
964
965        dev[1].connect("vht", key_mgmt="NONE", scan_freq="5200")
966        hwsim_utils.test_connectivity(dev[1], hapd)
967
968        if dev[1].get_status_field("ieee80211ac") != '1':
969            raise Exception("VHT not enabled as part of channel switch")
970    finally:
971        dev[0].request("DISCONNECT")
972        dev[1].request("DISCONNECT")
973        if hapd:
974            hapd.request("DISABLE")
975        subprocess.call(['iw', 'reg', 'set', '00'])
976        dev[0].flush_scan_cache()
977        dev[1].flush_scan_cache()
978
979def test_ap_vht_csa_vht40_disable(dev, apdev):
980    """VHT CSA with VHT40 getting disabled"""
981    csa_supported(dev[0])
982    try:
983        hapd = None
984        params = {"ssid": "vht",
985                  "country_code": "US",
986                  "hw_mode": "a",
987                  "channel": "149",
988                  "ht_capab": "[HT40+]",
989                  "ieee80211n": "1",
990                  "ieee80211ac": "1",
991                  "vht_capab": "",
992                  "vht_oper_chwidth": "0",
993                  "vht_oper_centr_freq_seg0_idx": "0"}
994        hapd = hostapd.add_ap(apdev[0], params)
995        bssid = hapd.own_addr()
996
997        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5200 5745")
998        hwsim_utils.test_connectivity(dev[0], hapd)
999
1000        hapd.request("CHAN_SWITCH 5 5200 center_freq1=5210 sec_channel_offset=1 bandwidth=40 ht")
1001        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
1002        if ev is None:
1003            raise Exception("CSA finished event timed out")
1004        if "freq=5200" not in ev:
1005            raise Exception("Unexpected channel in CSA finished event")
1006        ev = dev[0].wait_event(["CTRL-EVENT-CHANNEL-SWITCH"], timeout=5)
1007        if ev is None:
1008            raise Exception("Channel switch event not seen")
1009        if "freq=5200" not in ev:
1010            raise Exception("Channel mismatch: " + ev)
1011        ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=5)
1012        if ev:
1013            # mac80211 does not support CSA to disable VHT, so the channel
1014            # switch will be followed by disconnection and attempt to reconnect.
1015            # Wait for that here to avoid failing the test case based on how
1016            # example the connectivity test would get timed compared to getting
1017            # disconnected or reconnected.
1018            dev[0].wait_connected()
1019        hwsim_utils.test_connectivity(dev[0], hapd)
1020
1021        dev[1].connect("vht", key_mgmt="NONE", scan_freq="5200")
1022        hwsim_utils.test_connectivity(dev[1], hapd)
1023
1024        if dev[1].get_status_field("ieee80211ac") == '1':
1025            raise Exception("VHT not disabled as part of channel switch")
1026    finally:
1027        dev[0].request("DISCONNECT")
1028        dev[1].request("DISCONNECT")
1029        if hapd:
1030            hapd.request("DISABLE")
1031        subprocess.call(['iw', 'reg', 'set', '00'])
1032        dev[0].flush_scan_cache()
1033        dev[1].flush_scan_cache()
1034
1035def test_ap_vht_on_24ghz(dev, apdev):
1036    """Subset of VHT features on 2.4 GHz"""
1037    hapd = None
1038    params = {"ssid": "test-vht-2g",
1039              "hw_mode": "g",
1040              "channel": "1",
1041              "ieee80211n": "1",
1042              "vendor_vht": "1",
1043              "vht_capab": "[MAX-MPDU-11454]",
1044              "vht_oper_chwidth": "0",
1045              "vht_oper_centr_freq_seg0_idx": "1"}
1046    hapd = hostapd.add_ap(apdev[0], params)
1047    try:
1048        if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd1300904c0400bf0c3240820feaff0000eaff0000"):
1049            raise Exception("Failed to add vendor element")
1050        dev[0].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
1051        hapd.wait_sta()
1052        hwsim_utils.test_connectivity(dev[0], hapd)
1053        sta = hapd.get_sta(dev[0].own_addr())
1054        if '[VENDOR_VHT]' not in sta['flags']:
1055            raise Exception("No VENDOR_VHT STA flag")
1056
1057        dev[1].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
1058        hapd.wait_sta()
1059        sta = hapd.get_sta(dev[1].own_addr())
1060        if '[VENDOR_VHT]' in sta['flags']:
1061            raise Exception("Unexpected VENDOR_VHT STA flag")
1062
1063        status = dev[0].get_status()
1064        if 'wifi_generation' in status:
1065            if status['wifi_generation'] != "4":
1066                raise Exception("Unexpected wifi_generation value: " + status['wifi_generation'])
1067
1068        status = dev[1].get_status()
1069        if 'wifi_generation' in status:
1070            if status['wifi_generation'] != "4":
1071                raise Exception("Unexpected wifi_generation value(2): " + status['wifi_generation'])
1072    finally:
1073        dev[0].request("VENDOR_ELEM_REMOVE 13 *")
1074
1075def test_ap_vht_on_24ghz_2(dev, apdev):
1076    """Subset of VHT features on 2.4 GHz (2)"""
1077    hapd = None
1078    params = {"ssid": "test-vht-2g",
1079              "hw_mode": "g",
1080              "channel": "1",
1081              "ieee80211n": "1",
1082              "ieee80211ac": "1",
1083              "vendor_vht": "1",
1084              "vht_capab": "[MAX-MPDU-11454]",
1085              "vht_oper_chwidth": "0",
1086              "vht_oper_centr_freq_seg0_idx": "1"}
1087    hapd = hostapd.add_ap(apdev[0], params)
1088    try:
1089        if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 bf0cfa048003aaaa0000aaaa0000dd1300904c0400bf0c3240820feaff0000eaff0000"):
1090            raise Exception("Failed to add vendor element")
1091        dev[0].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
1092        hapd.wait_sta()
1093        hwsim_utils.test_connectivity(dev[0], hapd)
1094        sta = hapd.get_sta(dev[0].own_addr())
1095        if '[VHT]' not in sta['flags']:
1096            raise Exception("No VHT STA flag")
1097
1098        dev[1].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
1099        hapd.wait_sta()
1100        sta = hapd.get_sta(dev[1].own_addr())
1101        if '[VENDOR_VHT]' in sta['flags']:
1102            raise Exception("Unexpected VENDOR_VHT STA flag")
1103        if '[VHT]' in sta['flags']:
1104            raise Exception("Unexpected VHT STA flag")
1105
1106        status = dev[0].get_status()
1107        if 'wifi_generation' in status:
1108            if status['wifi_generation'] != "4":
1109                raise Exception("Unexpected wifi_generation value: " + status['wifi_generation'])
1110
1111        status = dev[1].get_status()
1112        if 'wifi_generation' in status:
1113            if status['wifi_generation'] != "4":
1114                raise Exception("Unexpected wifi_generation value(2): " + status['wifi_generation'])
1115    finally:
1116        dev[0].request("VENDOR_ELEM_REMOVE 13 *")
1117
1118def test_prefer_vht40(dev, apdev):
1119    """Preference on VHT40 over HT40"""
1120    clear_scan_cache(apdev[0])
1121    try:
1122        hapd = None
1123        hapd2 = None
1124
1125        params = {"ssid": "test",
1126                  "country_code": "FI",
1127                  "hw_mode": "a",
1128                  "channel": "36",
1129                  "ieee80211n": "1",
1130                  "ht_capab": "[HT40+]"}
1131        hapd = hostapd.add_ap(apdev[0], params)
1132        bssid = apdev[0]['bssid']
1133
1134        params = {"ssid": "test",
1135                  "country_code": "FI",
1136                  "hw_mode": "a",
1137                  "channel": "36",
1138                  "ieee80211n": "1",
1139                  "ieee80211ac": "1",
1140                  "ht_capab": "[HT40+]",
1141                  "vht_capab": "",
1142                  "vht_oper_chwidth": "0",
1143                  "vht_oper_centr_freq_seg0_idx": "0"}
1144        hapd2 = hostapd.add_ap(apdev[1], params)
1145        bssid2 = apdev[1]['bssid']
1146
1147        dev[0].scan_for_bss(bssid, freq=5180)
1148        dev[0].scan_for_bss(bssid2, freq=5180)
1149        dev[0].connect("test", scan_freq="5180", key_mgmt="NONE")
1150        if dev[0].get_status_field('bssid') != bssid2:
1151            raise Exception("Unexpected BSS selected")
1152
1153        est = dev[0].get_bss(bssid)['est_throughput']
1154        if est != "135000":
1155            raise Exception("Unexpected BSS0 est_throughput: " + est)
1156
1157        est = dev[0].get_bss(bssid2)['est_throughput']
1158        if est != "180001":
1159            raise Exception("Unexpected BSS1 est_throughput: " + est)
1160    finally:
1161        dev[0].request("DISCONNECT")
1162        disable_hapd(hapd)
1163        disable_hapd(hapd2)
1164        clear_regdom_dev(dev)
1165
1166def test_ap_vht80_pwr_constraint(dev, apdev):
1167    """VHT with 80 MHz channel width and local power constraint"""
1168    clear_scan_cache(apdev[0])
1169    hapd = None
1170    try:
1171        params = {"ssid": "vht",
1172                  "country_code": "FI",
1173                  "hw_mode": "a",
1174                  "channel": "36",
1175                  "ht_capab": "[HT40+]",
1176                  "ieee80211d": "1",
1177                  "local_pwr_constraint": "3",
1178                  "ieee80211n": "1",
1179                  "ieee80211ac": "1",
1180                  "vht_oper_chwidth": "1",
1181                  "vht_oper_centr_freq_seg0_idx": "42"}
1182        hapd = hostapd.add_ap(apdev[0], params)
1183
1184        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
1185        dev[0].wait_regdom(country_ie=True)
1186    except Exception as e:
1187        if isinstance(e, Exception) and str(e) == "AP startup failed":
1188            if not vht_supported():
1189                raise HwsimSkip("80 MHz channel not supported in regulatory information")
1190        raise
1191    finally:
1192        if hapd:
1193            hapd.request("DISABLE")
1194        dev[0].disconnect_and_stop_scan()
1195        subprocess.call(['iw', 'reg', 'set', '00'])
1196        dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
1197        dev[0].flush_scan_cache()
1198
1199def test_ap_vht_use_sta_nsts(dev, apdev):
1200    """VHT with 80 MHz channel width and use_sta_nsts=1"""
1201    clear_scan_cache(apdev[0])
1202    try:
1203        hapd = None
1204        params = {"ssid": "vht",
1205                  "country_code": "FI",
1206                  "hw_mode": "a",
1207                  "channel": "36",
1208                  "ht_capab": "[HT40+]",
1209                  "ieee80211n": "1",
1210                  "ieee80211ac": "1",
1211                  "vht_oper_chwidth": "1",
1212                  "vht_oper_centr_freq_seg0_idx": "42",
1213                  "use_sta_nsts": "1"}
1214        hapd = hostapd.add_ap(apdev[0], params)
1215        bssid = apdev[0]['bssid']
1216
1217        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
1218        hwsim_utils.test_connectivity(dev[0], hapd)
1219    except Exception as e:
1220        if isinstance(e, Exception) and str(e) == "AP startup failed":
1221            if not vht_supported():
1222                raise HwsimSkip("80 MHz channel not supported in regulatory information")
1223        raise
1224    finally:
1225        clear_regdom(hapd, dev)
1226
1227def test_ap_vht_tkip(dev, apdev):
1228    """VHT and TKIP"""
1229    skip_without_tkip(dev[0])
1230    clear_scan_cache(apdev[0])
1231    try:
1232        hapd = None
1233        params = {"ssid": "vht",
1234                  "wpa": "1",
1235                  "wpa_key_mgmt": "WPA-PSK",
1236                  "wpa_pairwise": "TKIP",
1237                  "wpa_passphrase": "12345678",
1238                  "country_code": "FI",
1239                  "hw_mode": "a",
1240                  "channel": "36",
1241                  "ht_capab": "[HT40+]",
1242                  "ieee80211n": "1",
1243                  "ieee80211ac": "1",
1244                  "vht_oper_chwidth": "1",
1245                  "vht_oper_centr_freq_seg0_idx": "42"}
1246        hapd = hostapd.add_ap(apdev[0], params)
1247        bssid = apdev[0]['bssid']
1248
1249        dev[0].connect("vht", psk="12345678", scan_freq="5180")
1250        hwsim_utils.test_connectivity(dev[0], hapd)
1251        sig = dev[0].request("SIGNAL_POLL").splitlines()
1252        if "FREQUENCY=5180" not in sig:
1253            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
1254        if "WIDTH=20 MHz (no HT)" not in sig:
1255            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
1256        status = hapd.get_status()
1257        logger.info("hostapd STATUS: " + str(status))
1258        if status["ieee80211n"] != "0":
1259            raise Exception("Unexpected STATUS ieee80211n value")
1260        if status["ieee80211ac"] != "0":
1261            raise Exception("Unexpected STATUS ieee80211ac value")
1262        if status["secondary_channel"] != "0":
1263            raise Exception("Unexpected STATUS secondary_channel value")
1264    except Exception as e:
1265        if isinstance(e, Exception) and str(e) == "AP startup failed":
1266            if not vht_supported():
1267                raise HwsimSkip("80 MHz channel not supported in regulatory information")
1268        raise
1269    finally:
1270        dev[0].request("DISCONNECT")
1271        clear_regdom(hapd, dev)
1272
1273def test_ap_vht_40_fallback_to_20(devs, apdevs):
1274    """VHT and 40 MHz channel configuration falling back to 20 MHz"""
1275    dev = devs[0]
1276    ap = apdevs[0]
1277    try:
1278        hapd = None
1279        params = {"ssid": "test-vht40",
1280                  "country_code": "US",
1281                  "hw_mode": "a",
1282                  "basic_rates": "60 120 240",
1283                  "channel": "161",
1284                  "ieee80211d": "1",
1285                  "ieee80211h": "1",
1286                  "ieee80211n": "1",
1287                  "ieee80211ac": "1",
1288                  "ht_capab": "[HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40]",
1289                  "vht_capab": "[RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC1][MAX-MPDU-11454][MAX-A-MPDU-LEN-EXP7]",
1290                  "vht_oper_chwidth": "0",
1291                  "vht_oper_centr_freq_seg0_idx": "155"}
1292        hapd = hostapd.add_ap(ap, params)
1293        dev.connect("test-vht40", scan_freq="5805", key_mgmt="NONE")
1294        dev.wait_regdom(country_ie=True)
1295        hwsim_utils.test_connectivity(dev, hapd)
1296    finally:
1297        clear_regdom(hapd, devs)
1298
1299def test_ap_vht80_to_24g_ht(dev, apdev):
1300    """VHT with 80 MHz channel width reconfigured to 2.4 GHz HT"""
1301    try:
1302        hapd = None
1303        params = {"ssid": "vht",
1304                  "country_code": "FI",
1305                  "hw_mode": "a",
1306                  "channel": "36",
1307                  "ht_capab": "[HT40+]",
1308                  "ieee80211n": "1",
1309                  "ieee80211ac": "1",
1310                  "vht_oper_chwidth": "1",
1311                  "vht_capab": "[MAX-MPDU-11454]",
1312                  "vht_oper_centr_freq_seg0_idx": "42"}
1313        hapd = hostapd.add_ap(apdev[0], params)
1314        bssid = apdev[0]['bssid']
1315
1316        hapd.disable()
1317        hapd.set("ieee80211ac", "0")
1318        hapd.set("hw_mode", "g")
1319        hapd.set("channel", "1")
1320        hapd.set("ht_capab", "")
1321        hapd.set("vht_capab", "")
1322        hapd.enable()
1323
1324        dev[0].connect("vht", key_mgmt="NONE", scan_freq="2412")
1325    except Exception as e:
1326        if isinstance(e, Exception) and str(e) == "AP startup failed":
1327            if not vht_supported():
1328                raise HwsimSkip("80 MHz channel not supported in regulatory information")
1329        raise
1330    finally:
1331        dev[0].request("DISCONNECT")
1332        clear_regdom(hapd, dev)
1333
1334def test_ap_vht_csa_invalid(dev, apdev):
1335    """VHT CSA with invalid parameters"""
1336    csa_supported(dev[0])
1337    try:
1338        hapd = None
1339        params = {"ssid": "vht",
1340                  "country_code": "US",
1341                  "hw_mode": "a",
1342                  "channel": "149",
1343                  "ht_capab": "[HT40+]",
1344                  "ieee80211n": "1",
1345                  "ieee80211ac": "0"}
1346        hapd = hostapd.add_ap(apdev[0], params)
1347
1348        tests = ["5 5765 center_freq1=5180",
1349                 "5 5765 bandwidth=40",
1350                 "5 5765 bandwidth=40 center_freq2=5180",
1351                 "5 5765 bandwidth=40 sec_channel_offset=1 center_freq1=5180",
1352                 "5 5765 bandwidth=40 sec_channel_offset=-1 center_freq1=5180",
1353                 "5 5765 bandwidth=40 sec_channel_offset=2 center_freq1=5180",
1354                 "5 5765 bandwidth=80",
1355                 "5 5765 bandwidth=80 sec_channel_offset=-1",
1356                 "5 5765 bandwidth=80 center_freq1=5755",
1357                 "5 5765 bandwidth=80 sec_channel_offset=1 center_freq1=5180",
1358                 "5 5765 bandwidth=80 sec_channel_offset=-1 center_freq1=5180",
1359                 "5 5765 bandwidth=80 sec_channel_offset=2 center_freq1=5180",
1360                 "5 5765 bandwidth=80 sec_channel_offset=-1 center_freq1=5775 center_freq2=5775",
1361                 "5 5765 bandwidth=160",
1362                 "5 5765 bandwidth=160 center_freq1=5755",
1363                 "5 5765 bandwidth=160 center_freq1=5755 center_freq2=5755",
1364                 "5 5765 bandwidth=160 center_freq1=5755 center_freq2=5755 sec_channel_offset=-1",
1365                 "5 5765 bandwidth=160 center_freq1=5754 sec_channel_offset=1",
1366                 "5 5765 bandwidth=160 center_freq1=5755 sec_channel_offset=2",
1367                 "5 5765 sec_channel_offset=-1"]
1368        for t in tests:
1369            if "FAIL" not in hapd.request("CHAN_SWITCH " + t):
1370                raise Exception("Invalid CHAN_SWITCH accepted: " + t)
1371
1372        hapd.request("CHAN_SWITCH 5 5765 bandwidth=160 center_freq1=5755 sec_channel_offset=1")
1373        ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
1374        if ev is None:
1375            raise Exception("Timeout on AP-CSA-FINISHED")
1376
1377        hapd.request("CHAN_SWITCH 5 5765 bandwidth=160 center_freq1=5775 sec_channel_offset=-1")
1378        time.sleep(1)
1379    finally:
1380        if hapd:
1381            hapd.request("DISABLE")
1382        subprocess.call(['iw', 'reg', 'set', '00'])
1383