tests: Subset of VHT functionality on 2.4 GHz
[mech_eap.git] / tests / hwsim / test_ap_vht.py
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
8 import logging
9 logger = logging.getLogger()
10 import os
11 import subprocess, time
12
13 import hwsim_utils
14 import hostapd
15 from utils import HwsimSkip
16 from test_dfs import wait_dfs_event
17 from test_ap_csa import csa_supported
18
19 def vht_supported():
20     cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
21     reg = cmd.stdout.read()
22     if "@ 80)" in reg or "@ 160)" in reg:
23         return True
24     return False
25
26 def test_ap_vht80(dev, apdev):
27     """VHT with 80 MHz channel width"""
28     try:
29         hapd = None
30         params = { "ssid": "vht",
31                    "country_code": "FI",
32                    "hw_mode": "a",
33                    "channel": "36",
34                    "ht_capab": "[HT40+]",
35                    "ieee80211n": "1",
36                    "ieee80211ac": "1",
37                    "vht_oper_chwidth": "1",
38                    "vht_oper_centr_freq_seg0_idx": "42" }
39         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
40
41         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
42         hwsim_utils.test_connectivity(dev[0], hapd)
43     except Exception, e:
44         if isinstance(e, Exception) and str(e) == "AP startup failed":
45             if not vht_supported():
46                 raise HwsimSkip("80 MHz channel not supported in regulatory information")
47         raise
48     finally:
49         dev[0].request("DISCONNECT")
50         if hapd:
51             hapd.request("DISABLE")
52         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
53         dev[0].flush_scan_cache()
54
55 def test_ap_vht80_params(dev, apdev):
56     """VHT with 80 MHz channel width and number of optional features enabled"""
57     try:
58         hapd = None
59         params = { "ssid": "vht",
60                    "country_code": "FI",
61                    "hw_mode": "a",
62                    "channel": "36",
63                    "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
64                    "ieee80211n": "1",
65                    "ieee80211ac": "1",
66                    "vht_oper_chwidth": "1",
67                    "vht_capab": "[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP0]",
68                    "vht_oper_centr_freq_seg0_idx": "42",
69                    "require_vht": "1" }
70         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
71
72         dev[1].connect("vht", key_mgmt="NONE", scan_freq="5180",
73                        disable_vht="1", wait_connect=False)
74         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
75         ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
76         if ev is None:
77             raise Exception("Association rejection timed out")
78         if "status_code=104" not in ev:
79             raise Exception("Unexpected rejection status code")
80         dev[1].request("DISCONNECT")
81         hwsim_utils.test_connectivity(dev[0], hapd)
82     except Exception, e:
83         if isinstance(e, Exception) and str(e) == "AP startup failed":
84             if not vht_supported():
85                 raise HwsimSwkip("80 MHz channel not supported in regulatory information")
86         raise
87     finally:
88         dev[0].request("DISCONNECT")
89         dev[1].request("DISCONNECT")
90         if hapd:
91             hapd.request("DISABLE")
92         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
93         dev[0].flush_scan_cache()
94         dev[1].flush_scan_cache()
95
96 def test_ap_vht_20(devs, apdevs):
97     """VHT and 20 MHz channel"""
98     dev = devs[0]
99     ap = apdevs[0]
100     try:
101         hapd = None
102         params = { "ssid": "test-vht20",
103                    "country_code": "DE",
104                    "hw_mode": "a",
105                    "channel": "36",
106                    "ieee80211n": "1",
107                    "ieee80211ac": "1",
108                    "ht_capab": "",
109                    "vht_capab": "",
110                    "vht_oper_chwidth": "0",
111                    "vht_oper_centr_freq_seg0_idx": "0",
112                    "supported_rates": "60 120 240 360 480 540",
113                    "require_vht": "1",
114                  }
115         hapd = hostapd.add_ap(ap['ifname'], params)
116         dev.connect("test-vht20", scan_freq="5180", key_mgmt="NONE")
117         hwsim_utils.test_connectivity(dev, hapd)
118     finally:
119         dev.request("DISCONNECT")
120         if hapd:
121             hapd.request("DISABLE")
122         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
123         dev.flush_scan_cache()
124
125 def test_ap_vht_40(devs, apdevs):
126     """VHT and 40 MHz channel"""
127     dev = devs[0]
128     ap = apdevs[0]
129     try:
130         hapd = None
131         params = { "ssid": "test-vht40",
132                    "country_code": "DE",
133                    "hw_mode": "a",
134                    "channel": "36",
135                    "ieee80211n": "1",
136                    "ieee80211ac": "1",
137                    "ht_capab": "[HT40+]",
138                    "vht_capab": "",
139                    "vht_oper_chwidth": "0",
140                    "vht_oper_centr_freq_seg0_idx": "0",
141                  }
142         hapd = hostapd.add_ap(ap['ifname'], params)
143         dev.connect("test-vht40", scan_freq="5180", key_mgmt="NONE")
144         hwsim_utils.test_connectivity(dev, hapd)
145     finally:
146         dev.request("DISCONNECT")
147         if hapd:
148             hapd.request("DISABLE")
149         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
150         dev.flush_scan_cache()
151
152 def test_ap_vht_capab_not_supported(dev, apdev):
153     """VHT configuration with driver not supporting all vht_capab entries"""
154     try:
155         params = { "ssid": "vht",
156                    "country_code": "FI",
157                    "hw_mode": "a",
158                    "channel": "36",
159                    "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
160                    "ieee80211n": "1",
161                    "ieee80211ac": "1",
162                    "vht_oper_chwidth": "1",
163                    "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][SOUNDING-DIMENSION-2][MU-BEAMFORMER][MU-BEAMFORMEE][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]",
164                    "vht_oper_centr_freq_seg0_idx": "42",
165                    "require_vht": "1" }
166         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
167         ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
168         if ev is None:
169             raise Exception("Startup failure not reported")
170         for i in range(1, 7):
171             if "OK" not in hapd.request("SET vht_capab [MAX-A-MPDU-LEN-EXP%d]" % i):
172                 raise Exception("Unexpected SET failure")
173     finally:
174         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
175
176 def test_ap_vht160(dev, apdev):
177     """VHT with 160 MHz channel width"""
178     try:
179         hapd = None
180         hapd2 = None
181         params = { "ssid": "vht",
182                    "country_code": "FI",
183                    "hw_mode": "a",
184                    "channel": "36",
185                    "ht_capab": "[HT40+]",
186                    "ieee80211n": "1",
187                    "ieee80211ac": "1",
188                    "vht_oper_chwidth": "2",
189                    "vht_oper_centr_freq_seg0_idx": "50",
190                    'ieee80211d': '1',
191                    'ieee80211h': '1' }
192         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
193
194         ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
195         if "DFS-CAC-START" not in ev:
196             raise Exception("Unexpected DFS event")
197
198         state = hapd.get_status_field("state")
199         if state != "DFS":
200             if state == "DISABLED" and not os.path.exists("dfs"):
201                 # Not all systems have recent enough CRDA version and
202                 # wireless-regdb changes to support 160 MHz and DFS. For now,
203                 # do not report failures for this test case.
204                 raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
205             raise Exception("Unexpected interface state: " + state)
206
207         params = { "ssid": "vht2",
208                    "country_code": "FI",
209                    "hw_mode": "a",
210                    "channel": "100",
211                    "ht_capab": "[HT40+]",
212                    "ieee80211n": "1",
213                    "ieee80211ac": "1",
214                    "vht_oper_chwidth": "2",
215                    "vht_oper_centr_freq_seg0_idx": "114",
216                    'ieee80211d': '1',
217                    'ieee80211h': '1' }
218         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
219
220         ev = wait_dfs_event(hapd2, "DFS-CAC-START", 5)
221         if "DFS-CAC-START" not in ev:
222             raise Exception("Unexpected DFS event(2)")
223
224         state = hapd2.get_status_field("state")
225         if state != "DFS":
226             raise Exception("Unexpected interface state(2): " + state)
227
228         logger.info("Waiting for CAC to complete")
229
230         ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
231         if "success=1" not in ev:
232             raise Exception("CAC failed")
233         if "freq=5180" not in ev:
234             raise Exception("Unexpected DFS freq result")
235
236         ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
237         if not ev:
238             raise Exception("AP setup timed out")
239
240         state = hapd.get_status_field("state")
241         if state != "ENABLED":
242             raise Exception("Unexpected interface state")
243
244         ev = wait_dfs_event(hapd2, "DFS-CAC-COMPLETED", 70)
245         if "success=1" not in ev:
246             raise Exception("CAC failed(2)")
247         if "freq=5500" not in ev:
248             raise Exception("Unexpected DFS freq result(2)")
249
250         ev = hapd2.wait_event(["AP-ENABLED"], timeout=5)
251         if not ev:
252             raise Exception("AP setup timed out(2)")
253
254         state = hapd2.get_status_field("state")
255         if state != "ENABLED":
256             raise Exception("Unexpected interface state(2)")
257
258         freq = hapd2.get_status_field("freq")
259         if freq != "5500":
260             raise Exception("Unexpected frequency(2)")
261
262         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
263         hwsim_utils.test_connectivity(dev[0], hapd)
264         sig = dev[0].request("SIGNAL_POLL").splitlines()
265         if "FREQUENCY=5180" not in sig:
266             raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
267         if "WIDTH=160 MHz" not in sig:
268             raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
269         dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5500")
270         hwsim_utils.test_connectivity(dev[1], hapd2)
271         sig = dev[1].request("SIGNAL_POLL").splitlines()
272         if "FREQUENCY=5500" not in sig:
273             raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
274         if "WIDTH=160 MHz" not in sig:
275             raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
276     except Exception, e:
277         if isinstance(e, Exception) and str(e) == "AP startup failed":
278             if not vht_supported():
279                 raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
280         raise
281     finally:
282         dev[0].request("DISCONNECT")
283         dev[1].request("DISCONNECT")
284         if hapd:
285             hapd.request("DISABLE")
286         if hapd2:
287             hapd2.request("DISABLE")
288         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
289         dev[0].flush_scan_cache()
290         dev[1].flush_scan_cache()
291
292 def test_ap_vht80plus80(dev, apdev):
293     """VHT with 80+80 MHz channel width"""
294     try:
295         hapd = None
296         hapd2 = None
297         params = { "ssid": "vht",
298                    "country_code": "US",
299                    "hw_mode": "a",
300                    "channel": "52",
301                    "ht_capab": "[HT40+]",
302                    "ieee80211n": "1",
303                    "ieee80211ac": "1",
304                    "vht_oper_chwidth": "3",
305                    "vht_oper_centr_freq_seg0_idx": "58",
306                    "vht_oper_centr_freq_seg1_idx": "155",
307                    'ieee80211d': '1',
308                    'ieee80211h': '1' }
309         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
310         # This will actually fail since DFS on 80+80 is not yet supported
311         ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
312         # ignore result to avoid breaking the test once 80+80 DFS gets enabled
313
314         params = { "ssid": "vht2",
315                    "country_code": "US",
316                    "hw_mode": "a",
317                    "channel": "36",
318                    "ht_capab": "[HT40+]",
319                    "ieee80211n": "1",
320                    "ieee80211ac": "1",
321                    "vht_oper_chwidth": "3",
322                    "vht_oper_centr_freq_seg0_idx": "42",
323                    "vht_oper_centr_freq_seg1_idx": "155" }
324         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
325
326         ev = hapd2.wait_event(["AP-ENABLED"], timeout=5)
327         if not ev:
328             raise Exception("AP setup timed out(2)")
329
330         state = hapd2.get_status_field("state")
331         if state != "ENABLED":
332             raise Exception("Unexpected interface state(2)")
333
334         dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5180")
335         hwsim_utils.test_connectivity(dev[1], hapd2)
336         sig = dev[1].request("SIGNAL_POLL").splitlines()
337         if "FREQUENCY=5180" not in sig:
338             raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
339         if "WIDTH=80+80 MHz" not in sig:
340             raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
341         if "CENTER_FRQ1=5210" not in sig:
342             raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
343         if "CENTER_FRQ2=5775" not in sig:
344             raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
345     except Exception, e:
346         if isinstance(e, Exception) and str(e) == "AP startup failed":
347             if not vht_supported():
348                 raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
349         raise
350     finally:
351         dev[0].request("DISCONNECT")
352         dev[1].request("DISCONNECT")
353         if hapd:
354             hapd.request("DISABLE")
355         if hapd2:
356             hapd2.request("DISABLE")
357         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
358         dev[0].flush_scan_cache()
359         dev[1].flush_scan_cache()
360
361 def test_ap_vht80_csa(dev, apdev):
362     """VHT with 80 MHz channel width and CSA"""
363     csa_supported(dev[0])
364     try:
365         hapd = None
366         params = { "ssid": "vht",
367                    "country_code": "US",
368                    "hw_mode": "a",
369                    "channel": "149",
370                    "ht_capab": "[HT40+]",
371                    "ieee80211n": "1",
372                    "ieee80211ac": "1",
373                    "vht_oper_chwidth": "1",
374                    "vht_oper_centr_freq_seg0_idx": "155" }
375         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
376
377         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
378         hwsim_utils.test_connectivity(dev[0], hapd)
379
380         hapd.request("CHAN_SWITCH 5 5180 ht vht blocktx center_freq1=5210 sec_channel_offset=1 bandwidth=80")
381         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
382         if ev is None:
383             raise Exception("CSA finished event timed out")
384         if "freq=5180" not in ev:
385             raise Exception("Unexpected channel in CSA finished event")
386         time.sleep(0.5)
387         hwsim_utils.test_connectivity(dev[0], hapd)
388
389         hapd.request("CHAN_SWITCH 5 5745")
390         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
391         if ev is None:
392             raise Exception("CSA finished event timed out")
393         if "freq=5745" not in ev:
394             raise Exception("Unexpected channel in CSA finished event")
395         time.sleep(0.5)
396         hwsim_utils.test_connectivity(dev[0], hapd)
397
398         # This CSA to same channel will fail in kernel, so use this only for
399         # extra code coverage.
400         hapd.request("CHAN_SWITCH 5 5745")
401         hapd.wait_event(["AP-CSA-FINISHED"], timeout=1)
402     except Exception, e:
403         if isinstance(e, Exception) and str(e) == "AP startup failed":
404             if not vht_supported():
405                 raise HwsimSkip("80 MHz channel not supported in regulatory information")
406         raise
407     finally:
408         dev[0].request("DISCONNECT")
409         if hapd:
410             hapd.request("DISABLE")
411         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
412         dev[0].flush_scan_cache()
413
414 def test_ap_vht_on_24ghz(dev, apdev):
415     """Subset of VHT features on 2.4 GHz"""
416     hapd = None
417     params = { "ssid": "test-vht-2g",
418                "hw_mode": "g",
419                "channel": "1",
420                "ieee80211n": "1",
421                "vendor_vht": "1",
422                "vht_capab": "[MAX-MPDU-11454]",
423                "vht_oper_chwidth": "0",
424                "vht_oper_centr_freq_seg0_idx": "1"
425     }
426     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
427     try:
428         if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd1300904c0400bf0c3240820feaff0000eaff0000"):
429             raise Exception("Failed to add vendor element")
430         dev[0].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
431         hwsim_utils.test_connectivity(dev[0], hapd)
432         sta = hapd.get_sta(dev[0].own_addr())
433         if '[VENDOR_VHT]' not in sta['flags']:
434             raise Exception("No VENDOR_VHT STA flag")
435
436         dev[1].connect("test-vht-2g", scan_freq="2412", key_mgmt="NONE")
437         sta = hapd.get_sta(dev[1].own_addr())
438         if '[VENDOR_VHT]' in sta['flags']:
439             raise Exception("Unexpected VENDOR_VHT STA flag")
440     finally:
441         dev[0].request("VENDOR_ELEM_REMOVE 13 *")