tests: Try to clear scan results after regulatory domain changes
[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 test_dfs import wait_dfs_event
16 from test_ap_csa import csa_supported
17
18 def vht_supported():
19     cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
20     reg = cmd.stdout.read()
21     if "@ 80)" in reg or "@ 160)" in reg:
22         return True
23     return False
24
25 def test_ap_vht80(dev, apdev):
26     """VHT with 80 MHz channel width"""
27     try:
28         hapd = None
29         params = { "ssid": "vht",
30                    "country_code": "FI",
31                    "hw_mode": "a",
32                    "channel": "36",
33                    "ht_capab": "[HT40+]",
34                    "ieee80211n": "1",
35                    "ieee80211ac": "1",
36                    "vht_oper_chwidth": "1",
37                    "vht_oper_centr_freq_seg0_idx": "42" }
38         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
39
40         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
41         hwsim_utils.test_connectivity(dev[0], hapd)
42     except Exception, e:
43         if isinstance(e, Exception) and str(e) == "AP startup failed":
44             if not vht_supported():
45                 logger.info("80 MHz channel not supported in regulatory information")
46                 return "skip"
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                 logger.info("80 MHz channel not supported in regulatory information")
86                 return "skip"
87         raise
88     finally:
89         dev[0].request("DISCONNECT")
90         dev[1].request("DISCONNECT")
91         if hapd:
92             hapd.request("DISABLE")
93         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
94         dev[0].flush_scan_cache()
95         dev[1].flush_scan_cache()
96
97 def test_ap_vht_20(devs, apdevs):
98     """VHT and 20 MHz channel"""
99     dev = devs[0]
100     ap = apdevs[0]
101     try:
102         hapd = None
103         params = { "ssid": "test-vht20",
104                    "country_code": "DE",
105                    "hw_mode": "a",
106                    "channel": "36",
107                    "ieee80211n": "1",
108                    "ieee80211ac": "1",
109                    "ht_capab": "",
110                    "vht_capab": "",
111                    "vht_oper_chwidth": "0",
112                    "vht_oper_centr_freq_seg0_idx": "0",
113                    "supported_rates": "60 120 240 360 480 540",
114                    "require_vht": "1",
115                  }
116         hapd = hostapd.add_ap(ap['ifname'], params)
117         dev.connect("test-vht20", scan_freq="5180", key_mgmt="NONE")
118         hwsim_utils.test_connectivity(dev, hapd)
119     finally:
120         dev.request("DISCONNECT")
121         if hapd:
122             hapd.request("DISABLE")
123         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
124         dev.flush_scan_cache()
125
126 def test_ap_vht_capab_not_supported(dev, apdev):
127     """VHT configuration with driver not supporting all vht_capab entries"""
128     try:
129         params = { "ssid": "vht",
130                    "country_code": "FI",
131                    "hw_mode": "a",
132                    "channel": "36",
133                    "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
134                    "ieee80211n": "1",
135                    "ieee80211ac": "1",
136                    "vht_oper_chwidth": "1",
137                    "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]",
138                    "vht_oper_centr_freq_seg0_idx": "42",
139                    "require_vht": "1" }
140         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
141         ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
142         if ev is None:
143             raise Exception("Startup failure not reported")
144         for i in range(1, 7):
145             if "OK" not in hapd.request("SET vht_capab [MAX-A-MPDU-LEN-EXP%d]" % i):
146                 raise Exception("Unexpected SET failure")
147     finally:
148         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
149
150 def test_ap_vht160(dev, apdev):
151     """VHT with 160 MHz channel width"""
152     try:
153         hapd = None
154         hapd2 = None
155         params = { "ssid": "vht",
156                    "country_code": "FI",
157                    "hw_mode": "a",
158                    "channel": "36",
159                    "ht_capab": "[HT40+]",
160                    "ieee80211n": "1",
161                    "ieee80211ac": "1",
162                    "vht_oper_chwidth": "2",
163                    "vht_oper_centr_freq_seg0_idx": "50",
164                    'ieee80211d': '1',
165                    'ieee80211h': '1' }
166         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
167
168         ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
169         if "DFS-CAC-START" not in ev:
170             raise Exception("Unexpected DFS event")
171
172         state = hapd.get_status_field("state")
173         if state != "DFS":
174             if state == "DISABLED" and not os.path.exists("dfs"):
175                 # Not all systems have recent enough CRDA version and
176                 # wireless-regdb changes to support 160 MHz and DFS. For now,
177                 # do not report failures for this test case.
178                 return "skip"
179             raise Exception("Unexpected interface state: " + state)
180
181         params = { "ssid": "vht2",
182                    "country_code": "FI",
183                    "hw_mode": "a",
184                    "channel": "100",
185                    "ht_capab": "[HT40+]",
186                    "ieee80211n": "1",
187                    "ieee80211ac": "1",
188                    "vht_oper_chwidth": "2",
189                    "vht_oper_centr_freq_seg0_idx": "114",
190                    'ieee80211d': '1',
191                    'ieee80211h': '1' }
192         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
193
194         ev = wait_dfs_event(hapd2, "DFS-CAC-START", 5)
195         if "DFS-CAC-START" not in ev:
196             raise Exception("Unexpected DFS event(2)")
197
198         state = hapd2.get_status_field("state")
199         if state != "DFS":
200             raise Exception("Unexpected interface state(2): " + state)
201
202         logger.info("Waiting for CAC to complete")
203
204         ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
205         if "success=1" not in ev:
206             raise Exception("CAC failed")
207         if "freq=5180" not in ev:
208             raise Exception("Unexpected DFS freq result")
209
210         ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
211         if not ev:
212             raise Exception("AP setup timed out")
213
214         state = hapd.get_status_field("state")
215         if state != "ENABLED":
216             raise Exception("Unexpected interface state")
217
218         ev = wait_dfs_event(hapd2, "DFS-CAC-COMPLETED", 70)
219         if "success=1" not in ev:
220             raise Exception("CAC failed(2)")
221         if "freq=5500" not in ev:
222             raise Exception("Unexpected DFS freq result(2)")
223
224         ev = hapd2.wait_event(["AP-ENABLED"], timeout=5)
225         if not ev:
226             raise Exception("AP setup timed out(2)")
227
228         state = hapd2.get_status_field("state")
229         if state != "ENABLED":
230             raise Exception("Unexpected interface state(2)")
231
232         freq = hapd2.get_status_field("freq")
233         if freq != "5500":
234             raise Exception("Unexpected frequency(2)")
235
236         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
237         hwsim_utils.test_connectivity(dev[0], hapd)
238         sig = dev[0].request("SIGNAL_POLL").splitlines()
239         if "FREQUENCY=5180" not in sig:
240             raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
241         if "WIDTH=160 MHz" not in sig:
242             raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
243         dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5500")
244         hwsim_utils.test_connectivity(dev[1], hapd2)
245         sig = dev[1].request("SIGNAL_POLL").splitlines()
246         if "FREQUENCY=5500" not in sig:
247             raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
248         if "WIDTH=160 MHz" not in sig:
249             raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
250     except Exception, e:
251         if isinstance(e, Exception) and str(e) == "AP startup failed":
252             if not vht_supported():
253                 logger.info("80/160 MHz channel not supported in regulatory information")
254                 return "skip"
255         raise
256     finally:
257         dev[0].request("DISCONNECT")
258         dev[1].request("DISCONNECT")
259         if hapd:
260             hapd.request("DISABLE")
261         if hapd2:
262             hapd2.request("DISABLE")
263         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
264         dev[0].flush_scan_cache()
265         dev[1].flush_scan_cache()
266
267 def test_ap_vht80plus80(dev, apdev):
268     """VHT with 80+80 MHz channel width"""
269     try:
270         hapd = None
271         hapd2 = None
272         params = { "ssid": "vht",
273                    "country_code": "US",
274                    "hw_mode": "a",
275                    "channel": "52",
276                    "ht_capab": "[HT40+]",
277                    "ieee80211n": "1",
278                    "ieee80211ac": "1",
279                    "vht_oper_chwidth": "3",
280                    "vht_oper_centr_freq_seg0_idx": "58",
281                    "vht_oper_centr_freq_seg1_idx": "155",
282                    'ieee80211d': '1',
283                    'ieee80211h': '1' }
284         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
285         # This will actually fail since DFS on 80+80 is not yet supported
286         ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
287         # ignore result to avoid breaking the test once 80+80 DFS gets enabled
288
289         params = { "ssid": "vht2",
290                    "country_code": "US",
291                    "hw_mode": "a",
292                    "channel": "36",
293                    "ht_capab": "[HT40+]",
294                    "ieee80211n": "1",
295                    "ieee80211ac": "1",
296                    "vht_oper_chwidth": "3",
297                    "vht_oper_centr_freq_seg0_idx": "42",
298                    "vht_oper_centr_freq_seg1_idx": "155" }
299         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
300
301         ev = hapd2.wait_event(["AP-ENABLED"], timeout=5)
302         if not ev:
303             raise Exception("AP setup timed out(2)")
304
305         state = hapd2.get_status_field("state")
306         if state != "ENABLED":
307             raise Exception("Unexpected interface state(2)")
308
309         dev[1].connect("vht2", key_mgmt="NONE", scan_freq="5180")
310         hwsim_utils.test_connectivity(dev[1], hapd2)
311         sig = dev[1].request("SIGNAL_POLL").splitlines()
312         if "FREQUENCY=5180" not in sig:
313             raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
314         if "WIDTH=80+80 MHz" not in sig:
315             raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
316         if "CENTER_FRQ1=5210" not in sig:
317             raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
318         if "CENTER_FRQ2=5775" not in sig:
319             raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
320     except Exception, e:
321         if isinstance(e, Exception) and str(e) == "AP startup failed":
322             if not vht_supported():
323                 logger.info("80/160 MHz channel not supported in regulatory information")
324                 return "skip"
325         raise
326     finally:
327         dev[0].request("DISCONNECT")
328         dev[1].request("DISCONNECT")
329         if hapd:
330             hapd.request("DISABLE")
331         if hapd2:
332             hapd2.request("DISABLE")
333         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
334         dev[0].flush_scan_cache()
335         dev[1].flush_scan_cache()
336
337 def test_ap_vht80_csa(dev, apdev):
338     """VHT with 80 MHz channel width and CSA"""
339     if not csa_supported(dev[0]):
340         return "skip"
341     try:
342         hapd = None
343         params = { "ssid": "vht",
344                    "country_code": "US",
345                    "hw_mode": "a",
346                    "channel": "149",
347                    "ht_capab": "[HT40+]",
348                    "ieee80211n": "1",
349                    "ieee80211ac": "1",
350                    "vht_oper_chwidth": "1",
351                    "vht_oper_centr_freq_seg0_idx": "155" }
352         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
353
354         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
355         hwsim_utils.test_connectivity(dev[0], hapd)
356
357         hapd.request("CHAN_SWITCH 5 5180 ht vht blocktx center_freq1=5210 sec_channel_offset=1 bandwidth=80")
358         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
359         if ev is None:
360             raise Exception("CSA finished event timed out")
361         if "freq=5180" not in ev:
362             raise Exception("Unexpected channel in CSA finished event")
363         time.sleep(0.5)
364         hwsim_utils.test_connectivity(dev[0], hapd)
365
366         hapd.request("CHAN_SWITCH 5 5745")
367         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
368         if ev is None:
369             raise Exception("CSA finished event timed out")
370         if "freq=5745" not in ev:
371             raise Exception("Unexpected channel in CSA finished event")
372         time.sleep(0.5)
373         hwsim_utils.test_connectivity(dev[0], hapd)
374
375         # This CSA to same channel will fail in kernel, so use this only for
376         # extra code coverage.
377         hapd.request("CHAN_SWITCH 5 5745")
378         hapd.wait_event(["AP-CSA-FINISHED"], timeout=1)
379     except Exception, e:
380         if isinstance(e, Exception) and str(e) == "AP startup failed":
381             if not vht_supported():
382                 logger.info("80 MHz channel not supported in regulatory information")
383                 return "skip"
384         raise
385     finally:
386         dev[0].request("DISCONNECT")
387         if hapd:
388             hapd.request("DISABLE")
389         subprocess.call(['sudo', 'iw', 'reg', 'set', '00'])
390         dev[0].flush_scan_cache()