Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / 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     if ev is None:
772         raise Exception("Association rejection timed out")
773     if "status_code=27" not in ev:
774         raise Exception("Unexpected rejection status code")
775     dev[2].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
776                    ht_mcs="0x01 00 00 00 00 00 00 00 00 00",
777                    disable_max_amsdu="1", ampdu_factor="2",
778                    ampdu_density="1", disable_ht40="1", disable_sgi="1",
779                    disable_ldpc="1")
780
781 def test_ap_require_ht_limited_rates(dev, apdev):
782     """Require HT with limited supported rates"""
783     params = { "ssid": "require-ht",
784                "supported_rates": "60 120 240 360 480 540",
785                "require_ht": "1" }
786     hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
787
788     dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
789                    disable_ht="1", wait_connect=False)
790     dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
791     ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
792     if ev is None:
793         raise Exception("Association rejection timed out")
794     if "status_code=27" not in ev:
795         raise Exception("Unexpected rejection status code")
796
797 def test_ap_ht_capab_not_supported(dev, apdev):
798     """HT configuration with driver not supporting all ht_capab entries"""
799     params = { "ssid": "test-ht40",
800                "channel": "5",
801                "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]"}
802     hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
803     if "FAIL" not in hapd.request("ENABLE"):
804         raise Exception("Unexpected ENABLE success")
805
806 def test_ap_ht_40mhz_intolerant_sta(dev, apdev):
807     """Associated STA indicating 40 MHz intolerant"""
808     clear_scan_cache(apdev[0]['ifname'])
809     params = { "ssid": "intolerant",
810                "channel": "6",
811                "ht_capab": "[HT40-]" }
812     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
813     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
814         raise Exception("Unexpected num_sta_ht40_intolerant value")
815     if hapd.get_status_field("secondary_channel") != "-1":
816         raise Exception("Unexpected secondary_channel")
817
818     dev[0].connect("intolerant", key_mgmt="NONE", scan_freq="2437")
819     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
820         raise Exception("Unexpected num_sta_ht40_intolerant value")
821     if hapd.get_status_field("secondary_channel") != "-1":
822         raise Exception("Unexpected secondary_channel")
823
824     dev[2].connect("intolerant", key_mgmt="NONE", scan_freq="2437",
825                    ht40_intolerant="1")
826     time.sleep(1)
827     if hapd.get_status_field("num_sta_ht40_intolerant") != "1":
828         raise Exception("Unexpected num_sta_ht40_intolerant value (expected 1)")
829     if hapd.get_status_field("secondary_channel") != "0":
830         raise Exception("Unexpected secondary_channel (did not disable 40 MHz)")
831
832     dev[2].request("DISCONNECT")
833     time.sleep(1)
834     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
835         raise Exception("Unexpected num_sta_ht40_intolerant value (expected 0)")
836     if hapd.get_status_field("secondary_channel") != "-1":
837         raise Exception("Unexpected secondary_channel (did not re-enable 40 MHz)")
838
839 def test_ap_ht_40mhz_intolerant_ap(dev, apdev):
840     """Associated STA reports 40 MHz intolerant AP after association"""
841     clear_scan_cache(apdev[0]['ifname'])
842     params = { "ssid": "ht",
843                "channel": "6",
844                "ht_capab": "[HT40-]",
845                "obss_interval": "3" }
846     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
847
848     dev[0].connect("ht", key_mgmt="NONE", scan_freq="2437")
849
850     if hapd.get_status_field("secondary_channel") != "-1":
851         raise Exception("Unexpected secondary channel information")
852
853     logger.info("Start 40 MHz intolerant AP")
854     params = { "ssid": "intolerant",
855                "channel": "5",
856                "ht_capab": "[40-INTOLERANT]" }
857     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
858
859     logger.info("Waiting for co-ex report from STA")
860     ok = False
861     for i in range(0, 20):
862         time.sleep(1)
863         if hapd.get_status_field("secondary_channel") == "0":
864             logger.info("AP moved to 20 MHz channel")
865             ok = True
866             break
867     if not ok:
868         raise Exception("AP did not move to 20 MHz channel")
869
870     if "OK" not in hapd2.request("DISABLE"):
871         raise Exception("Failed to disable 40 MHz intolerant AP")
872
873     # make sure the intolerant AP disappears from scan results more quickly
874     dev[0].scan(type="ONLY", freq="2432", only_new=True)
875     dev[0].scan(type="ONLY", freq="2432", only_new=True)
876     dev[0].dump_monitor()
877
878     logger.info("Waiting for AP to move back to 40 MHz channel")
879     ok = False
880     for i in range(0, 30):
881         time.sleep(1)
882         if hapd.get_status_field("secondary_channel") == "-1":
883             logger.info("AP moved to 40 MHz channel")
884             ok = True
885             break
886     if not ok:
887         raise Exception("AP did not move to 40 MHz channel")
888
889 def test_ap_ht40_csa(dev, apdev):
890     """HT with 40 MHz channel width and CSA"""
891     csa_supported(dev[0])
892     try:
893         hapd = None
894         params = { "ssid": "ht",
895                    "country_code": "US",
896                    "hw_mode": "a",
897                    "channel": "36",
898                    "ht_capab": "[HT40+]",
899                    "ieee80211n": "1" }
900         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
901
902         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
903         hwsim_utils.test_connectivity(dev[0], hapd)
904
905         hapd.request("CHAN_SWITCH 5 5200 ht sec_channel_offset=-1 bandwidth=40")
906         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
907         if ev is None:
908             raise Exception("CSA finished event timed out")
909         if "freq=5200" not in ev:
910             raise Exception("Unexpected channel in CSA finished event")
911         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
912         if ev is not None:
913             raise Exception("Unexpected STA disconnection during CSA")
914         hwsim_utils.test_connectivity(dev[0], hapd)
915
916         hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
917         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
918         if ev is None:
919             raise Exception("CSA finished event timed out")
920         if "freq=5180" not in ev:
921             raise Exception("Unexpected channel in CSA finished event")
922         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
923         if ev is not None:
924             raise Exception("Unexpected STA disconnection during CSA")
925         hwsim_utils.test_connectivity(dev[0], hapd)
926     finally:
927         dev[0].request("DISCONNECT")
928         if hapd:
929             hapd.request("DISABLE")
930         subprocess.call(['iw', 'reg', 'set', '00'])
931         dev[0].flush_scan_cache()
932
933 def test_ap_ht40_csa2(dev, apdev):
934     """HT with 40 MHz channel width and CSA"""
935     csa_supported(dev[0])
936     try:
937         hapd = None
938         params = { "ssid": "ht",
939                    "country_code": "US",
940                    "hw_mode": "a",
941                    "channel": "36",
942                    "ht_capab": "[HT40+]",
943                    "ieee80211n": "1" }
944         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
945
946         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
947         hwsim_utils.test_connectivity(dev[0], hapd)
948
949         hapd.request("CHAN_SWITCH 5 5220 ht sec_channel_offset=1 bandwidth=40")
950         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
951         if ev is None:
952             raise Exception("CSA finished event timed out")
953         if "freq=5220" not in ev:
954             raise Exception("Unexpected channel in CSA finished event")
955         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
956         if ev is not None:
957             raise Exception("Unexpected STA disconnection during CSA")
958         hwsim_utils.test_connectivity(dev[0], hapd)
959
960         hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
961         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
962         if ev is None:
963             raise Exception("CSA finished event timed out")
964         if "freq=5180" not in ev:
965             raise Exception("Unexpected channel in CSA finished event")
966         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
967         if ev is not None:
968             raise Exception("Unexpected STA disconnection during CSA")
969         hwsim_utils.test_connectivity(dev[0], hapd)
970     finally:
971         dev[0].request("DISCONNECT")
972         if hapd:
973             hapd.request("DISABLE")
974         subprocess.call(['iw', 'reg', 'set', '00'])
975         dev[0].flush_scan_cache()
976
977 def test_ap_ht40_csa3(dev, apdev):
978     """HT with 40 MHz channel width and CSA"""
979     csa_supported(dev[0])
980     try:
981         hapd = None
982         params = { "ssid": "ht",
983                    "country_code": "US",
984                    "hw_mode": "a",
985                    "channel": "36",
986                    "ht_capab": "[HT40+]",
987                    "ieee80211n": "1" }
988         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
989
990         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
991         hwsim_utils.test_connectivity(dev[0], hapd)
992
993         hapd.request("CHAN_SWITCH 5 5240 ht sec_channel_offset=-1 bandwidth=40")
994         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
995         if ev is None:
996             raise Exception("CSA finished event timed out")
997         if "freq=5240" not in ev:
998             raise Exception("Unexpected channel in CSA finished event")
999         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
1000         if ev is not None:
1001             raise Exception("Unexpected STA disconnection during CSA")
1002         hwsim_utils.test_connectivity(dev[0], hapd)
1003
1004         hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
1005         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
1006         if ev is None:
1007             raise Exception("CSA finished event timed out")
1008         if "freq=5180" not in ev:
1009             raise Exception("Unexpected channel in CSA finished event")
1010         ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
1011         if ev is not None:
1012             raise Exception("Unexpected STA disconnection during CSA")
1013         hwsim_utils.test_connectivity(dev[0], hapd)
1014     finally:
1015         dev[0].request("DISCONNECT")
1016         if hapd:
1017             hapd.request("DISABLE")
1018         subprocess.call(['iw', 'reg', 'set', '00'])
1019         dev[0].flush_scan_cache()
1020
1021 def test_ap_ht_smps(dev, apdev):
1022     """SMPS AP configuration options"""
1023     params = { "ssid": "ht1", "ht_capab": "[SMPS-STATIC]" }
1024     try:
1025         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1026     except:
1027         raise HwsimSkip("Assume mac80211_hwsim was not recent enough to support SMPS")
1028     params = { "ssid": "ht2", "ht_capab": "[SMPS-DYNAMIC]" }
1029     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1030
1031     dev[0].connect("ht1", key_mgmt="NONE", scan_freq="2412")
1032     dev[1].connect("ht2", key_mgmt="NONE", scan_freq="2412")
1033     hwsim_utils.test_connectivity(dev[0], hapd)
1034     hwsim_utils.test_connectivity(dev[1], hapd2)
1035
1036 def test_prefer_ht20(dev, apdev):
1037     """Preference on HT20 over no-HT"""
1038     params = { "ssid": "test",
1039                "channel": "1",
1040                "ieee80211n": "0" }
1041     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1042     bssid = apdev[0]['bssid']
1043     params = { "ssid": "test",
1044                "channel": "1",
1045                "ieee80211n": "1" }
1046     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1047     bssid2 = apdev[1]['bssid']
1048
1049     dev[0].scan_for_bss(bssid, freq=2412)
1050     dev[0].scan_for_bss(bssid2, freq=2412)
1051     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
1052     if dev[0].get_status_field('bssid') != bssid2:
1053         raise Exception("Unexpected BSS selected")
1054
1055     est = dev[0].get_bss(bssid)['est_throughput']
1056     if est != "54000":
1057         raise Exception("Unexpected BSS0 est_throughput: " + est)
1058
1059     est = dev[0].get_bss(bssid2)['est_throughput']
1060     if est != "65000":
1061         raise Exception("Unexpected BSS1 est_throughput: " + est)
1062
1063 def test_prefer_ht40(dev, apdev):
1064     """Preference on HT40 over HT20"""
1065     params = { "ssid": "test",
1066                "channel": "1",
1067                "ieee80211n": "1" }
1068     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1069     bssid = apdev[0]['bssid']
1070     params = { "ssid": "test",
1071                "channel": "1",
1072                "ieee80211n": "1",
1073                "ht_capab": "[HT40+]" }
1074     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1075     bssid2 = apdev[1]['bssid']
1076
1077     dev[0].scan_for_bss(bssid, freq=2412)
1078     dev[0].scan_for_bss(bssid2, freq=2412)
1079     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
1080     if dev[0].get_status_field('bssid') != bssid2:
1081         raise Exception("Unexpected BSS selected")
1082
1083     est = dev[0].get_bss(bssid)['est_throughput']
1084     if est != "65000":
1085         raise Exception("Unexpected BSS0 est_throughput: " + est)
1086
1087     est = dev[0].get_bss(bssid2)['est_throughput']
1088     if est != "135000":
1089         raise Exception("Unexpected BSS1 est_throughput: " + est)
1090
1091 def test_prefer_ht20_during_roam(dev, apdev):
1092     """Preference on HT20 over no-HT in roaming consideration"""
1093     params = { "ssid": "test",
1094                "channel": "1",
1095                "ieee80211n": "0" }
1096     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1097     bssid = apdev[0]['bssid']
1098
1099     dev[0].scan_for_bss(bssid, freq=2412)
1100     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
1101
1102     params = { "ssid": "test",
1103                "channel": "1",
1104                "ieee80211n": "1" }
1105     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1106     bssid2 = apdev[1]['bssid']
1107     dev[0].scan_for_bss(bssid2, freq=2412)
1108     dev[0].scan(freq=2412)
1109     dev[0].wait_connected()
1110     
1111     if dev[0].get_status_field('bssid') != bssid2:
1112         raise Exception("Unexpected BSS selected")
1113
1114 def test_ap_ht40_5ghz_invalid_pair(dev, apdev):
1115     """HT40 on 5 GHz with invalid channel pair"""
1116     clear_scan_cache(apdev[0]['ifname'])
1117     try:
1118         params = { "ssid": "test-ht40",
1119                    "hw_mode": "a",
1120                    "channel": "40",
1121                    "country_code": "US",
1122                    "ht_capab": "[HT40+]"}
1123         hapd = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
1124         ev = hapd.wait_event(["AP-DISABLED"], timeout=10)
1125         if not ev:
1126             raise Exception("AP setup failure timed out")
1127     finally:
1128         subprocess.call(['iw', 'reg', 'set', '00'])