tests: Make tests using multi_check() more robust
[mech_eap.git] / tests / hwsim / test_ap_ht.py
1 # Test cases for HT operations with hostapd
2 # Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import time
8 import logging
9 logger = logging.getLogger()
10 import struct
11 import subprocess
12
13 import hostapd
14 from utils import HwsimSkip, alloc_fail
15 import hwsim_utils
16 from test_ap_csa import csa_supported
17
18 def clear_scan_cache(ifname):
19     subprocess.call(['ifconfig', ifname, 'up'])
20     subprocess.call(['iw', ifname, 'scan', 'trigger', 'freq', '2412', 'flush'])
21     time.sleep(0.1)
22     subprocess.call(['ifconfig', ifname, 'down'])
23
24 def test_ap_ht40_scan(dev, apdev):
25     """HT40 co-ex scan"""
26     clear_scan_cache(apdev[0]['ifname'])
27     params = { "ssid": "test-ht40",
28                "channel": "5",
29                "ht_capab": "[HT40-]"}
30     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
31
32     state = hapd.get_status_field("state")
33     if state != "HT_SCAN":
34         time.sleep(0.1)
35         state = hapd.get_status_field("state")
36         if state != "HT_SCAN":
37             raise Exception("Unexpected interface state - expected HT_SCAN")
38
39     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
40     if not ev:
41         raise Exception("AP setup timed out")
42
43     state = hapd.get_status_field("state")
44     if state != "ENABLED":
45         raise Exception("Unexpected interface state - expected ENABLED")
46
47     freq = hapd.get_status_field("freq")
48     if freq != "2432":
49         raise Exception("Unexpected frequency")
50     pri = hapd.get_status_field("channel")
51     if pri != "5":
52         raise Exception("Unexpected primary channel")
53     sec = hapd.get_status_field("secondary_channel")
54     if sec != "-1":
55         raise Exception("Unexpected secondary channel")
56
57     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
58
59 def test_ap_ht40_scan_conflict(dev, apdev):
60     """HT40 co-ex scan conflict"""
61     clear_scan_cache(apdev[0]['ifname'])
62     params = { "ssid": "test-ht40",
63                "channel": "6",
64                "ht_capab": "[HT40+]"}
65     hostapd.add_ap(apdev[1]['ifname'], params)
66
67     params = { "ssid": "test-ht40",
68                "channel": "5",
69                "ht_capab": "[HT40-]"}
70     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
71
72     state = hapd.get_status_field("state")
73     if state != "HT_SCAN":
74         time.sleep(0.1)
75         state = hapd.get_status_field("state")
76         if state != "HT_SCAN":
77             raise Exception("Unexpected interface state - expected HT_SCAN")
78
79     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
80     if not ev:
81         raise Exception("AP setup timed out")
82
83     state = hapd.get_status_field("state")
84     if state != "ENABLED":
85         raise Exception("Unexpected interface state - expected ENABLED")
86
87     freq = hapd.get_status_field("freq")
88     if freq != "2432":
89         raise Exception("Unexpected frequency")
90     pri = hapd.get_status_field("channel")
91     if pri != "5":
92         raise Exception("Unexpected primary channel")
93     sec = hapd.get_status_field("secondary_channel")
94     if sec != "0":
95         raise Exception("Unexpected secondary channel: " + sec)
96
97     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
98
99 def test_ap_ht40_scan_conflict2(dev, apdev):
100     """HT40 co-ex scan conflict (HT40-)"""
101     clear_scan_cache(apdev[0]['ifname'])
102     params = { "ssid": "test-ht40",
103                "channel": "11",
104                "ht_capab": "[HT40-]"}
105     hostapd.add_ap(apdev[1]['ifname'], params)
106
107     params = { "ssid": "test-ht40",
108                "channel": "1",
109                "ht_capab": "[HT40+]"}
110     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
111
112     state = hapd.get_status_field("state")
113     if state != "HT_SCAN":
114         time.sleep(0.1)
115         state = hapd.get_status_field("state")
116         if state != "HT_SCAN":
117             raise Exception("Unexpected interface state - expected HT_SCAN")
118
119     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
120     if not ev:
121         raise Exception("AP setup timed out")
122
123     state = hapd.get_status_field("state")
124     if state != "ENABLED":
125         raise Exception("Unexpected interface state - expected ENABLED")
126
127     freq = hapd.get_status_field("freq")
128     if freq != "2412":
129         raise Exception("Unexpected frequency")
130     pri = hapd.get_status_field("channel")
131     if pri != "1":
132         raise Exception("Unexpected primary channel")
133     sec = hapd.get_status_field("secondary_channel")
134     if sec != "0":
135         raise Exception("Unexpected secondary channel: " + sec)
136
137     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
138
139 def test_ap_ht40_scan_not_affected(dev, apdev):
140     """HT40 co-ex scan and other BSS not affected"""
141     clear_scan_cache(apdev[0]['ifname'])
142     params = { "ssid": "test-ht20",
143                "channel": "11" }
144     hostapd.add_ap(apdev[1]['ifname'], params)
145
146     subprocess.call(['ifconfig', apdev[0]['ifname'], 'up'])
147     subprocess.call(['iw', apdev[0]['ifname'], 'scan', 'trigger', 'freq', '2462'])
148     time.sleep(0.5)
149     subprocess.call(['iw', apdev[0]['ifname'], 'scan', 'dump'],
150                     stdout=open('/dev/null', 'w'))
151     time.sleep(0.1)
152     subprocess.call(['ifconfig', apdev[0]['ifname'], 'down'])
153
154     params = { "ssid": "test-ht40",
155                "channel": "1",
156                "ht_capab": "[HT40+]"}
157     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
158
159     state = hapd.get_status_field("state")
160     if state != "HT_SCAN":
161         time.sleep(0.1)
162         state = hapd.get_status_field("state")
163         if state != "HT_SCAN":
164             raise Exception("Unexpected interface state - expected HT_SCAN")
165
166     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
167     if not ev:
168         raise Exception("AP setup timed out")
169
170     state = hapd.get_status_field("state")
171     if state != "ENABLED":
172         raise Exception("Unexpected interface state - expected ENABLED")
173
174     freq = hapd.get_status_field("freq")
175     if freq != "2412":
176         raise Exception("Unexpected frequency")
177     pri = hapd.get_status_field("channel")
178     if pri != "1":
179         raise Exception("Unexpected primary channel")
180     sec = hapd.get_status_field("secondary_channel")
181     if sec != "1":
182         raise Exception("Unexpected secondary channel: " + sec)
183
184     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
185
186 def test_ap_ht40_scan_legacy_conflict(dev, apdev):
187     """HT40 co-ex scan conflict with legacy 20 MHz AP"""
188     clear_scan_cache(apdev[0]['ifname'])
189     params = { "ssid": "legacy-20",
190                "channel": "7", "ieee80211n": "0" }
191     hostapd.add_ap(apdev[1]['ifname'], params)
192
193     params = { "ssid": "test-ht40",
194                "channel": "5",
195                "ht_capab": "[HT40-]"}
196     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
197
198     state = hapd.get_status_field("state")
199     if state != "HT_SCAN":
200         time.sleep(0.1)
201         state = hapd.get_status_field("state")
202         if state != "HT_SCAN":
203             raise Exception("Unexpected interface state - expected HT_SCAN")
204
205     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
206     if not ev:
207         raise Exception("AP setup timed out")
208
209     state = hapd.get_status_field("state")
210     if state != "ENABLED":
211         raise Exception("Unexpected interface state - expected ENABLED")
212
213     freq = hapd.get_status_field("freq")
214     if freq != "2432":
215         raise Exception("Unexpected frequency: " + freq)
216     pri = hapd.get_status_field("channel")
217     if pri != "5":
218         raise Exception("Unexpected primary channel: " + pri)
219     sec = hapd.get_status_field("secondary_channel")
220     if sec != "0":
221         raise Exception("Unexpected secondary channel: " + sec)
222
223     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
224
225 def test_ap_ht40_scan_ht20_conflict(dev, apdev):
226     """HT40 co-ex scan conflict with HT 20 MHz AP"""
227     clear_scan_cache(apdev[0]['ifname'])
228     params = { "ssid": "ht-20",
229                "channel": "7", "ieee80211n": "1" }
230     hostapd.add_ap(apdev[1]['ifname'], params)
231
232     params = { "ssid": "test-ht40",
233                "channel": "5",
234                "ht_capab": "[HT40-]"}
235     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
236
237     state = hapd.get_status_field("state")
238     if state != "HT_SCAN":
239         time.sleep(0.1)
240         state = hapd.get_status_field("state")
241         if state != "HT_SCAN":
242             raise Exception("Unexpected interface state - expected HT_SCAN")
243
244     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
245     if not ev:
246         raise Exception("AP setup timed out")
247
248     state = hapd.get_status_field("state")
249     if state != "ENABLED":
250         raise Exception("Unexpected interface state - expected ENABLED")
251
252     freq = hapd.get_status_field("freq")
253     if freq != "2432":
254         raise Exception("Unexpected frequency: " + freq)
255     pri = hapd.get_status_field("channel")
256     if pri != "5":
257         raise Exception("Unexpected primary channel: " + pri)
258     sec = hapd.get_status_field("secondary_channel")
259     if sec != "0":
260         raise Exception("Unexpected secondary channel: " + sec)
261
262     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
263
264 def test_ap_ht40_scan_intolerant(dev, apdev):
265     """HT40 co-ex scan finding an AP advertising 40 MHz intolerant"""
266     clear_scan_cache(apdev[0]['ifname'])
267     params = { "ssid": "another-bss",
268                "channel": "1",
269                "ht_capab": "[40-INTOLERANT]" }
270     hostapd.add_ap(apdev[1]['ifname'], params)
271
272     params = { "ssid": "test-ht40",
273                "channel": "1",
274                "ht_capab": "[HT40+]"}
275     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
276
277     state = hapd.get_status_field("state")
278     if state != "HT_SCAN":
279         time.sleep(0.1)
280         state = hapd.get_status_field("state")
281         if state != "HT_SCAN":
282             raise Exception("Unexpected interface state - expected HT_SCAN")
283
284     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
285     if not ev:
286         raise Exception("AP setup timed out")
287
288     state = hapd.get_status_field("state")
289     if state != "ENABLED":
290         raise Exception("Unexpected interface state - expected ENABLED")
291
292     freq = hapd.get_status_field("freq")
293     if freq != "2412":
294         raise Exception("Unexpected frequency: " + freq)
295     pri = hapd.get_status_field("channel")
296     if pri != "1":
297         raise Exception("Unexpected primary channel: " + pri)
298     sec = hapd.get_status_field("secondary_channel")
299     if sec != "0":
300         raise Exception("Unexpected secondary channel: " + sec)
301
302     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
303
304 def test_ap_ht40_scan_match(dev, apdev):
305     """HT40 co-ex scan matching configuration"""
306     clear_scan_cache(apdev[0]['ifname'])
307     params = { "ssid": "test-ht40",
308                "channel": "5",
309                "ht_capab": "[HT40-]"}
310     hostapd.add_ap(apdev[1]['ifname'], params)
311
312     params = { "ssid": "test-ht40",
313                "channel": "5",
314                "ht_capab": "[HT40-]"}
315     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
316
317     state = hapd.get_status_field("state")
318     if state != "HT_SCAN":
319         time.sleep(0.1)
320         state = hapd.get_status_field("state")
321         if state != "HT_SCAN":
322             raise Exception("Unexpected interface state - expected HT_SCAN")
323
324     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
325     if not ev:
326         raise Exception("AP setup timed out")
327
328     state = hapd.get_status_field("state")
329     if state != "ENABLED":
330         raise Exception("Unexpected interface state - expected ENABLED")
331
332     freq = hapd.get_status_field("freq")
333     if freq != "2432":
334         raise Exception("Unexpected frequency")
335     pri = hapd.get_status_field("channel")
336     if pri != "5":
337         raise Exception("Unexpected primary channel")
338     sec = hapd.get_status_field("secondary_channel")
339     if sec != "-1":
340         raise Exception("Unexpected secondary channel: " + sec)
341
342     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
343
344 def test_ap_ht40_5ghz_match(dev, apdev):
345     """HT40 co-ex scan on 5 GHz with matching pri/sec channel"""
346     clear_scan_cache(apdev[0]['ifname'])
347     try:
348         hapd = None
349         hapd2 = None
350         params = { "ssid": "test-ht40",
351                    "hw_mode": "a",
352                    "channel": "36",
353                    "country_code": "US",
354                    "ht_capab": "[HT40+]"}
355         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
356
357         params = { "ssid": "test-ht40",
358                    "hw_mode": "a",
359                    "channel": "36",
360                    "ht_capab": "[HT40+]"}
361         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
362
363         state = hapd.get_status_field("state")
364         if state != "HT_SCAN":
365             time.sleep(0.1)
366             state = hapd.get_status_field("state")
367             if state != "HT_SCAN":
368                 raise Exception("Unexpected interface state - expected HT_SCAN")
369
370         ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
371         if not ev:
372             raise Exception("AP setup timed out")
373
374         state = hapd.get_status_field("state")
375         if state != "ENABLED":
376             raise Exception("Unexpected interface state - expected ENABLED")
377
378         freq = hapd.get_status_field("freq")
379         if freq != "5180":
380             raise Exception("Unexpected frequency")
381         pri = hapd.get_status_field("channel")
382         if pri != "36":
383             raise Exception("Unexpected primary channel")
384         sec = hapd.get_status_field("secondary_channel")
385         if sec != "1":
386             raise Exception("Unexpected secondary channel: " + sec)
387
388         dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
389     finally:
390         dev[0].request("DISCONNECT")
391         if hapd:
392             hapd.request("DISABLE")
393         if hapd2:
394             hapd2.request("DISABLE")
395         subprocess.call(['iw', 'reg', 'set', '00'])
396         dev[0].flush_scan_cache()
397
398 def test_ap_ht40_5ghz_switch(dev, apdev):
399     """HT40 co-ex scan on 5 GHz switching pri/sec channel"""
400     clear_scan_cache(apdev[0]['ifname'])
401     try:
402         hapd = None
403         hapd2 = None
404         params = { "ssid": "test-ht40",
405                    "hw_mode": "a",
406                    "channel": "36",
407                    "country_code": "US",
408                    "ht_capab": "[HT40+]"}
409         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
410
411         params = { "ssid": "test-ht40",
412                    "hw_mode": "a",
413                    "channel": "40",
414                    "ht_capab": "[HT40-]"}
415         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
416
417         state = hapd.get_status_field("state")
418         if state != "HT_SCAN":
419             time.sleep(0.1)
420             state = hapd.get_status_field("state")
421             if state != "HT_SCAN":
422                 raise Exception("Unexpected interface state - expected HT_SCAN")
423
424         ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
425         if not ev:
426             raise Exception("AP setup timed out")
427
428         state = hapd.get_status_field("state")
429         if state != "ENABLED":
430             raise Exception("Unexpected interface state - expected ENABLED")
431
432         freq = hapd.get_status_field("freq")
433         if freq != "5180":
434             raise Exception("Unexpected frequency: " + freq)
435         pri = hapd.get_status_field("channel")
436         if pri != "36":
437             raise Exception("Unexpected primary channel: " + pri)
438         sec = hapd.get_status_field("secondary_channel")
439         if sec != "1":
440             raise Exception("Unexpected secondary channel: " + sec)
441
442         dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
443     finally:
444         dev[0].request("DISCONNECT")
445         if hapd:
446             hapd.request("DISABLE")
447         if hapd2:
448             hapd2.request("DISABLE")
449         subprocess.call(['iw', 'reg', 'set', '00'])
450
451 def test_ap_ht40_5ghz_switch2(dev, apdev):
452     """HT40 co-ex scan on 5 GHz switching pri/sec channel (2)"""
453     clear_scan_cache(apdev[0]['ifname'])
454     try:
455         hapd = None
456         hapd2 = None
457         params = { "ssid": "test-ht40",
458                    "hw_mode": "a",
459                    "channel": "36",
460                    "country_code": "US",
461                    "ht_capab": "[HT40+]"}
462         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
463
464         id = dev[0].add_network()
465         dev[0].set_network(id, "mode", "2")
466         dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
467         dev[0].set_network(id, "key_mgmt", "NONE")
468         dev[0].set_network(id, "frequency", "5200")
469         dev[0].set_network(id, "scan_freq", "5200")
470         dev[0].select_network(id)
471         time.sleep(1)
472
473         params = { "ssid": "test-ht40",
474                    "hw_mode": "a",
475                    "channel": "40",
476                    "ht_capab": "[HT40-]"}
477         hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
478
479         state = hapd.get_status_field("state")
480         if state != "HT_SCAN":
481             time.sleep(0.1)
482             state = hapd.get_status_field("state")
483             if state != "HT_SCAN":
484                 raise Exception("Unexpected interface state - expected HT_SCAN")
485
486         ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
487         if not ev:
488             raise Exception("AP setup timed out")
489
490         state = hapd.get_status_field("state")
491         if state != "ENABLED":
492             raise Exception("Unexpected interface state - expected ENABLED")
493
494         freq = hapd.get_status_field("freq")
495         if freq != "5180":
496             raise Exception("Unexpected frequency: " + freq)
497         pri = hapd.get_status_field("channel")
498         if pri != "36":
499             raise Exception("Unexpected primary channel: " + pri)
500         sec = hapd.get_status_field("secondary_channel")
501         if sec != "1":
502             raise Exception("Unexpected secondary channel: " + sec)
503
504         dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
505     finally:
506         dev[0].request("DISCONNECT")
507         if hapd:
508             hapd.request("DISABLE")
509         if hapd2:
510             hapd2.request("DISABLE")
511         subprocess.call(['iw', 'reg', 'set', '00'])
512         dev[0].flush_scan_cache()
513
514 def test_obss_scan(dev, apdev):
515     """Overlapping BSS scan request"""
516     params = { "ssid": "obss-scan",
517                "channel": "6",
518                "ht_capab": "[HT40-]",
519                "obss_interval": "10" }
520     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
521
522     params = { "ssid": "another-bss",
523                "channel": "9",
524                "ieee80211n": "0" }
525     hostapd.add_ap(apdev[1]['ifname'], params)
526
527     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
528     hapd.set("ext_mgmt_frame_handling", "1")
529     logger.info("Waiting for OBSS scan to occur")
530     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15)
531     if ev is None:
532         raise Exception("Timed out while waiting for OBSS scan to start")
533     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
534     if ev is None:
535         raise Exception("Timed out while waiting for OBSS scan results")
536     received = False
537     for i in range(0, 4):
538         frame = hapd.mgmt_rx(timeout=5)
539         if frame is None:
540             raise Exception("MGMT RX wait timed out")
541         if frame['subtype'] != 13:
542             continue
543         payload = frame['payload']
544         if len(payload) < 3:
545             continue
546         (category, action, ie) = struct.unpack('BBB', payload[0:3])
547         if category != 4:
548             continue
549         if action != 0:
550             continue
551         if ie == 72:
552             logger.info("20/40 BSS Coexistence report received")
553             received = True
554             break
555     if not received:
556         raise Exception("20/40 BSS Coexistence report not seen")
557
558 def test_obss_scan_40_intolerant(dev, apdev):
559     """Overlapping BSS scan request with 40 MHz intolerant AP"""
560     params = { "ssid": "obss-scan",
561                "channel": "6",
562                "ht_capab": "[HT40-]",
563                "obss_interval": "10" }
564     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
565
566     params = { "ssid": "another-bss",
567                "channel": "7",
568                "ht_capab": "[40-INTOLERANT]" }
569     hostapd.add_ap(apdev[1]['ifname'], params)
570
571     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
572     hapd.set("ext_mgmt_frame_handling", "1")
573     logger.info("Waiting for OBSS scan to occur")
574     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15)
575     if ev is None:
576         raise Exception("Timed out while waiting for OBSS scan to start")
577     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
578     if ev is None:
579         raise Exception("Timed out while waiting for OBSS scan results")
580     received = False
581     for i in range(0, 4):
582         frame = hapd.mgmt_rx(timeout=5)
583         if frame is None:
584             raise Exception("MGMT RX wait timed out")
585         if frame['subtype'] != 13:
586             continue
587         payload = frame['payload']
588         if len(payload) < 3:
589             continue
590         (category, action, ie) = struct.unpack('BBB', payload[0:3])
591         if category != 4:
592             continue
593         if action != 0:
594             continue
595         if ie == 72:
596             logger.info("20/40 BSS Coexistence report received")
597             received = True
598             break
599     if not received:
600         raise Exception("20/40 BSS Coexistence report not seen")
601
602 def test_obss_coex_report_handling(dev, apdev):
603     """Overlapping BSS scan report handling with obss_interval=0"""
604     clear_scan_cache(apdev[0]['ifname'])
605     params = { "ssid": "obss-scan",
606                "channel": "6",
607                "ht_capab": "[HT40-]" }
608     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
609     bssid = apdev[0]['bssid']
610     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
611
612     sec = hapd.get_status_field("secondary_channel")
613     if sec != "-1":
614         raise Exception("AP is not using 40 MHz channel")
615
616     # 20/40 MHz co-ex report tests: number of invalid reports and a valid report
617     # that forces 20 MHz channel.
618     tests = [ '0400', '040048', '04004801', '0400480000', '0400490100',
619               '040048ff0000', '04004801ff49ff00', '04004801004900',
620               '0400480100490101', '0400480100490201ff',
621               '040048010449020005' ]
622     for msg in tests:
623         req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg)
624         if "OK" not in dev[0].request(req):
625             raise Exception("Could not send management frame")
626     time.sleep(0.5)
627     sec = hapd.get_status_field("secondary_channel")
628     if sec != "0":
629         raise Exception("AP did not move to 20 MHz channel")
630
631 def test_obss_coex_report_handling1(dev, apdev):
632     """Overlapping BSS scan report handling with obss_interval=1"""
633     clear_scan_cache(apdev[0]['ifname'])
634     params = { "ssid": "obss-scan",
635                "channel": "6",
636                "ht_capab": "[HT40+]",
637                "obss_interval": "1" }
638     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
639     bssid = apdev[0]['bssid']
640     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
641
642     sec = hapd.get_status_field("secondary_channel")
643     if sec != "1":
644         raise Exception("AP is not using 40 MHz channel")
645
646     # 20/40 MHz co-ex report forcing 20 MHz channel
647     msg = '040048010449020005'
648     req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg)
649     if "OK" not in dev[0].request(req):
650         raise Exception("Could not send management frame")
651     time.sleep(0.5)
652     sec = hapd.get_status_field("secondary_channel")
653     if sec != "0":
654         raise Exception("AP did not move to 20 MHz channel")
655
656     # No 20/40 MHz co-ex reports forcing 20 MHz channel during next interval
657     for i in range(20):
658         sec = hapd.get_status_field("secondary_channel")
659         if sec == "1":
660             break
661         time.sleep(0.5)
662     if sec != "1":
663         raise Exception("AP did not return to 40 MHz channel")
664
665 def test_olbc(dev, apdev):
666     """OLBC detection"""
667     params = { "ssid": "test-olbc",
668                "channel": "6",
669                "ht_capab": "[HT40-]",
670                "ap_table_expiration_time": "2" }
671     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
672     status = hapd.get_status()
673     if status['olbc'] != '0' or status['olbc_ht'] != '0':
674         raise Exception("Unexpected OLBC information")
675
676     params = { "ssid": "olbc-ap",
677                "hw_mode": "b",
678                "channel": "6",
679                "wmm_enabled": "0" }
680     hostapd.add_ap(apdev[1]['ifname'], params)
681     time.sleep(0.5)
682     status = hapd.get_status()
683     if status['olbc'] != '1' or status['olbc_ht'] != '1':
684         raise Exception("Missing OLBC information")
685
686     hapd_global = hostapd.HostapdGlobal()
687     hapd_global.remove(apdev[1]['ifname'])
688
689     logger.info("Waiting for OLBC state to time out")
690     cleared = False
691     for i in range(0, 15):
692         time.sleep(1)
693         status = hapd.get_status()
694         if status['olbc'] == '0' and status['olbc_ht'] == '0':
695             cleared = True
696             break
697     if not cleared:
698         raise Exception("OLBC state did nto time out")
699
700 def test_olbc_table_limit(dev, apdev):
701     """OLBC AP table size limit"""
702     ifname1 = apdev[0]['ifname']
703     ifname2 = apdev[0]['ifname'] + '-2'
704     ifname3 = apdev[0]['ifname'] + '-3'
705     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
706     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
707     hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
708
709     params = { "ssid": "test-olbc",
710                "channel": "1",
711                "ap_table_max_size": "2" }
712     hapd = hostapd.add_ap(apdev[1]['ifname'], params)
713
714     time.sleep(0.3)
715     with alloc_fail(hapd, 1, "ap_list_process_beacon"):
716         time.sleep(0.3)
717     hapd.set("ap_table_max_size", "1")
718     time.sleep(0.3)
719     hapd.set("ap_table_max_size", "0")
720     time.sleep(0.3)
721
722 def test_olbc_5ghz(dev, apdev):
723     """OLBC detection on 5 GHz"""
724     try:
725         hapd = None
726         hapd2 = None
727         params = { "ssid": "test-olbc",
728                    "country_code": "FI",
729                    "hw_mode": "a",
730                    "channel": "36",
731                    "ht_capab": "[HT40+]" }
732         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
733         status = hapd.get_status()
734         if status['olbc'] != '0' or status['olbc_ht'] != '0':
735             raise Exception("Unexpected OLBC information")
736
737         params = { "ssid": "olbc-ap",
738                    "country_code": "FI",
739                    "hw_mode": "a",
740                    "channel": "36",
741                    "ieee80211n": "0",
742                    "wmm_enabled": "0" }
743         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
744         found = False
745         for i in range(20):
746             time.sleep(0.1)
747             status = hapd.get_status()
748             logger.debug('olbc_ht: ' + status['olbc_ht'])
749             if status['olbc_ht'] == '1':
750                 found = True
751                 break
752         if not found:
753             raise Exception("Missing OLBC information")
754     finally:
755         if hapd:
756             hapd.request("DISABLE")
757         if hapd2:
758             hapd2.request("DISABLE")
759         subprocess.call(['iw', 'reg', 'set', '00'])
760
761 def test_ap_require_ht(dev, apdev):
762     """Require HT"""
763     params = { "ssid": "require-ht",
764                "require_ht": "1" }
765     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
766
767     dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
768                    disable_ht="1", wait_connect=False)
769     dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
770     ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
771     dev[1].request("DISCONNECT")
772     if ev is None:
773         raise Exception("Association rejection timed out")
774     if "status_code=27" not in ev:
775         raise Exception("Unexpected rejection status code")
776     dev[2].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
777                    ht_mcs="0x01 00 00 00 00 00 00 00 00 00",
778                    disable_max_amsdu="1", ampdu_factor="2",
779                    ampdu_density="1", disable_ht40="1", disable_sgi="1",
780                    disable_ldpc="1")
781
782 def test_ap_require_ht_limited_rates(dev, apdev):
783     """Require HT with limited supported rates"""
784     params = { "ssid": "require-ht",
785                "supported_rates": "60 120 240 360 480 540",
786                "require_ht": "1" }
787     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
788
789     dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
790                    disable_ht="1", wait_connect=False)
791     dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
792     ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
793     dev[1].request("DISCONNECT")
794     if ev is None:
795         raise Exception("Association rejection timed out")
796     if "status_code=27" not in ev:
797         raise Exception("Unexpected rejection status code")
798
799 def test_ap_ht_capab_not_supported(dev, apdev):
800     """HT configuration with driver not supporting all ht_capab entries"""
801     params = { "ssid": "test-ht40",
802                "channel": "5",
803                "ht_capab": "[HT40-][LDPC][SMPS-STATIC][SMPS-DYNAMIC][GF][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][RX-STBC12][RX-STBC123][DELAYED-BA][MAX-AMSDU-7935][DSSS_CCK-40][LSIG-TXOP-PROT]"}
804     hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
805     if "FAIL" not in hapd.request("ENABLE"):
806         raise Exception("Unexpected ENABLE success")
807
808 def test_ap_ht_40mhz_intolerant_sta(dev, apdev):
809     """Associated STA indicating 40 MHz intolerant"""
810     clear_scan_cache(apdev[0]['ifname'])
811     params = { "ssid": "intolerant",
812                "channel": "6",
813                "ht_capab": "[HT40-]" }
814     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
815     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
816         raise Exception("Unexpected num_sta_ht40_intolerant value")
817     if hapd.get_status_field("secondary_channel") != "-1":
818         raise Exception("Unexpected secondary_channel")
819
820     dev[0].connect("intolerant", key_mgmt="NONE", scan_freq="2437")
821     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
822         raise Exception("Unexpected num_sta_ht40_intolerant value")
823     if hapd.get_status_field("secondary_channel") != "-1":
824         raise Exception("Unexpected secondary_channel")
825
826     dev[2].connect("intolerant", key_mgmt="NONE", scan_freq="2437",
827                    ht40_intolerant="1")
828     time.sleep(1)
829     if hapd.get_status_field("num_sta_ht40_intolerant") != "1":
830         raise Exception("Unexpected num_sta_ht40_intolerant value (expected 1)")
831     if hapd.get_status_field("secondary_channel") != "0":
832         raise Exception("Unexpected secondary_channel (did not disable 40 MHz)")
833
834     dev[2].request("DISCONNECT")
835     time.sleep(1)
836     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
837         raise Exception("Unexpected num_sta_ht40_intolerant value (expected 0)")
838     if hapd.get_status_field("secondary_channel") != "-1":
839         raise Exception("Unexpected secondary_channel (did not re-enable 40 MHz)")
840
841 def test_ap_ht_40mhz_intolerant_ap(dev, apdev):
842     """Associated STA reports 40 MHz intolerant AP after association"""
843     clear_scan_cache(apdev[0]['ifname'])
844     params = { "ssid": "ht",
845                "channel": "6",
846                "ht_capab": "[HT40-]",
847                "obss_interval": "3" }
848     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
849
850     dev[0].connect("ht", key_mgmt="NONE", scan_freq="2437")
851
852     if hapd.get_status_field("secondary_channel") != "-1":
853         raise Exception("Unexpected secondary channel information")
854
855     logger.info("Start 40 MHz intolerant AP")
856     params = { "ssid": "intolerant",
857                "channel": "5",
858                "ht_capab": "[40-INTOLERANT]" }
859     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
860
861     logger.info("Waiting for co-ex report from STA")
862     ok = False
863     for i in range(0, 20):
864         time.sleep(1)
865         if hapd.get_status_field("secondary_channel") == "0":
866             logger.info("AP moved to 20 MHz channel")
867             ok = True
868             break
869     if not ok:
870         raise Exception("AP did not move to 20 MHz channel")
871
872     if "OK" not in hapd2.request("DISABLE"):
873         raise Exception("Failed to disable 40 MHz intolerant AP")
874
875     # make sure the intolerant AP disappears from scan results more quickly
876     dev[0].scan(type="ONLY", freq="2432", only_new=True)
877     dev[0].scan(type="ONLY", freq="2432", only_new=True)
878     dev[0].dump_monitor()
879
880     logger.info("Waiting for AP to move back to 40 MHz channel")
881     ok = False
882     for i in range(0, 30):
883         time.sleep(1)
884         if hapd.get_status_field("secondary_channel") == "-1":
885             logger.info("AP moved to 40 MHz channel")
886             ok = True
887             break
888     if not ok:
889         raise Exception("AP did not move to 40 MHz channel")
890
891 def test_ap_ht40_csa(dev, apdev):
892     """HT with 40 MHz channel width and CSA"""
893     csa_supported(dev[0])
894     try:
895         hapd = None
896         params = { "ssid": "ht",
897                    "country_code": "US",
898                    "hw_mode": "a",
899                    "channel": "36",
900                    "ht_capab": "[HT40+]",
901                    "ieee80211n": "1" }
902         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
903
904         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
905         hwsim_utils.test_connectivity(dev[0], hapd)
906
907         hapd.request("CHAN_SWITCH 5 5200 ht sec_channel_offset=-1 bandwidth=40")
908         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
909         if ev is None:
910             raise Exception("CSA finished event timed out")
911         if "freq=5200" not in ev:
912             raise Exception("Unexpected channel in CSA finished event")
913         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
914         if ev is not None:
915             raise Exception("Unexpected STA disconnection during CSA")
916         hwsim_utils.test_connectivity(dev[0], hapd)
917
918         hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
919         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
920         if ev is None:
921             raise Exception("CSA finished event timed out")
922         if "freq=5180" not in ev:
923             raise Exception("Unexpected channel in CSA finished event")
924         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
925         if ev is not None:
926             raise Exception("Unexpected STA disconnection during CSA")
927         hwsim_utils.test_connectivity(dev[0], hapd)
928     finally:
929         dev[0].request("DISCONNECT")
930         if hapd:
931             hapd.request("DISABLE")
932         subprocess.call(['iw', 'reg', 'set', '00'])
933         dev[0].flush_scan_cache()
934
935 def test_ap_ht40_csa2(dev, apdev):
936     """HT with 40 MHz channel width and CSA"""
937     csa_supported(dev[0])
938     try:
939         hapd = None
940         params = { "ssid": "ht",
941                    "country_code": "US",
942                    "hw_mode": "a",
943                    "channel": "36",
944                    "ht_capab": "[HT40+]",
945                    "ieee80211n": "1" }
946         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
947
948         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
949         hwsim_utils.test_connectivity(dev[0], hapd)
950
951         hapd.request("CHAN_SWITCH 5 5220 ht sec_channel_offset=1 bandwidth=40")
952         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
953         if ev is None:
954             raise Exception("CSA finished event timed out")
955         if "freq=5220" not in ev:
956             raise Exception("Unexpected channel in CSA finished event")
957         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
958         if ev is not None:
959             raise Exception("Unexpected STA disconnection during CSA")
960         hwsim_utils.test_connectivity(dev[0], hapd)
961
962         hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
963         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
964         if ev is None:
965             raise Exception("CSA finished event timed out")
966         if "freq=5180" not in ev:
967             raise Exception("Unexpected channel in CSA finished event")
968         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
969         if ev is not None:
970             raise Exception("Unexpected STA disconnection during CSA")
971         hwsim_utils.test_connectivity(dev[0], hapd)
972     finally:
973         dev[0].request("DISCONNECT")
974         if hapd:
975             hapd.request("DISABLE")
976         subprocess.call(['iw', 'reg', 'set', '00'])
977         dev[0].flush_scan_cache()
978
979 def test_ap_ht40_csa3(dev, apdev):
980     """HT with 40 MHz channel width and CSA"""
981     csa_supported(dev[0])
982     try:
983         hapd = None
984         params = { "ssid": "ht",
985                    "country_code": "US",
986                    "hw_mode": "a",
987                    "channel": "36",
988                    "ht_capab": "[HT40+]",
989                    "ieee80211n": "1" }
990         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
991
992         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
993         hwsim_utils.test_connectivity(dev[0], hapd)
994
995         hapd.request("CHAN_SWITCH 5 5240 ht sec_channel_offset=-1 bandwidth=40")
996         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
997         if ev is None:
998             raise Exception("CSA finished event timed out")
999         if "freq=5240" not in ev:
1000             raise Exception("Unexpected channel in CSA finished event")
1001         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
1002         if ev is not None:
1003             raise Exception("Unexpected STA disconnection during CSA")
1004         hwsim_utils.test_connectivity(dev[0], hapd)
1005
1006         hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
1007         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
1008         if ev is None:
1009             raise Exception("CSA finished event timed out")
1010         if "freq=5180" not in ev:
1011             raise Exception("Unexpected channel in CSA finished event")
1012         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
1013         if ev is not None:
1014             raise Exception("Unexpected STA disconnection during CSA")
1015         hwsim_utils.test_connectivity(dev[0], hapd)
1016     finally:
1017         dev[0].request("DISCONNECT")
1018         if hapd:
1019             hapd.request("DISABLE")
1020         subprocess.call(['iw', 'reg', 'set', '00'])
1021         dev[0].flush_scan_cache()
1022
1023 def test_ap_ht_smps(dev, apdev):
1024     """SMPS AP configuration options"""
1025     params = { "ssid": "ht1", "ht_capab": "[SMPS-STATIC]" }
1026     try:
1027         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1028     except:
1029         raise HwsimSkip("Assume mac80211_hwsim was not recent enough to support SMPS")
1030     params = { "ssid": "ht2", "ht_capab": "[SMPS-DYNAMIC]" }
1031     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1032
1033     dev[0].connect("ht1", key_mgmt="NONE", scan_freq="2412")
1034     dev[1].connect("ht2", key_mgmt="NONE", scan_freq="2412")
1035     hwsim_utils.test_connectivity(dev[0], hapd)
1036     hwsim_utils.test_connectivity(dev[1], hapd2)
1037
1038 def test_prefer_ht20(dev, apdev):
1039     """Preference on HT20 over no-HT"""
1040     params = { "ssid": "test",
1041                "channel": "1",
1042                "ieee80211n": "0" }
1043     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1044     bssid = apdev[0]['bssid']
1045     params = { "ssid": "test",
1046                "channel": "1",
1047                "ieee80211n": "1" }
1048     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1049     bssid2 = apdev[1]['bssid']
1050
1051     dev[0].scan_for_bss(bssid, freq=2412)
1052     dev[0].scan_for_bss(bssid2, freq=2412)
1053     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
1054     if dev[0].get_status_field('bssid') != bssid2:
1055         raise Exception("Unexpected BSS selected")
1056
1057     est = dev[0].get_bss(bssid)['est_throughput']
1058     if est != "54000":
1059         raise Exception("Unexpected BSS0 est_throughput: " + est)
1060
1061     est = dev[0].get_bss(bssid2)['est_throughput']
1062     if est != "65000":
1063         raise Exception("Unexpected BSS1 est_throughput: " + est)
1064
1065 def test_prefer_ht40(dev, apdev):
1066     """Preference on HT40 over HT20"""
1067     params = { "ssid": "test",
1068                "channel": "1",
1069                "ieee80211n": "1" }
1070     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1071     bssid = apdev[0]['bssid']
1072     params = { "ssid": "test",
1073                "channel": "1",
1074                "ieee80211n": "1",
1075                "ht_capab": "[HT40+]" }
1076     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1077     bssid2 = apdev[1]['bssid']
1078
1079     dev[0].scan_for_bss(bssid, freq=2412)
1080     dev[0].scan_for_bss(bssid2, freq=2412)
1081     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
1082     if dev[0].get_status_field('bssid') != bssid2:
1083         raise Exception("Unexpected BSS selected")
1084
1085     est = dev[0].get_bss(bssid)['est_throughput']
1086     if est != "65000":
1087         raise Exception("Unexpected BSS0 est_throughput: " + est)
1088
1089     est = dev[0].get_bss(bssid2)['est_throughput']
1090     if est != "135000":
1091         raise Exception("Unexpected BSS1 est_throughput: " + est)
1092
1093 def test_prefer_ht20_during_roam(dev, apdev):
1094     """Preference on HT20 over no-HT in roaming consideration"""
1095     params = { "ssid": "test",
1096                "channel": "1",
1097                "ieee80211n": "0" }
1098     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1099     bssid = apdev[0]['bssid']
1100
1101     dev[0].scan_for_bss(bssid, freq=2412)
1102     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
1103
1104     params = { "ssid": "test",
1105                "channel": "1",
1106                "ieee80211n": "1" }
1107     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1108     bssid2 = apdev[1]['bssid']
1109     dev[0].scan_for_bss(bssid2, freq=2412)
1110     dev[0].scan(freq=2412)
1111     dev[0].wait_connected()
1112     
1113     if dev[0].get_status_field('bssid') != bssid2:
1114         raise Exception("Unexpected BSS selected")
1115
1116 def test_ap_ht40_5ghz_invalid_pair(dev, apdev):
1117     """HT40 on 5 GHz with invalid channel pair"""
1118     clear_scan_cache(apdev[0]['ifname'])
1119     try:
1120         params = { "ssid": "test-ht40",
1121                    "hw_mode": "a",
1122                    "channel": "40",
1123                    "country_code": "US",
1124                    "ht_capab": "[HT40+]"}
1125         hapd = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
1126         ev = hapd.wait_event(["AP-DISABLED"], timeout=10)
1127         if not ev:
1128             raise Exception("AP setup failure timed out")
1129     finally:
1130         subprocess.call(['iw', 'reg', 'set', '00'])