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