1# Test cases for automatic channel selection with hostapd
2# Copyright (c) 2013-2018, 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
7import logging
8logger = logging.getLogger()
9import time
10
11import hostapd
12from utils import *
13from test_dfs import wait_dfs_event
14
15def force_prev_ap_on_24g(ap):
16    # For now, make sure the last operating channel was on 2.4 GHz band to get
17    # sufficient survey data from mac80211_hwsim.
18    hostapd.add_ap(ap, {"ssid": "open"})
19    time.sleep(0.1)
20    hostapd.remove_bss(ap)
21
22def force_prev_ap_on_5g(ap, country="US"):
23    # For now, make sure the last operating channel was on 5 GHz band to get
24    # sufficient survey data from mac80211_hwsim.
25    hostapd.add_ap(ap, {"ssid": "open", "hw_mode": "a",
26                        "channel": "36", "country_code": country})
27    time.sleep(0.1)
28    hostapd.remove_bss(ap)
29
30def force_prev_ap_on_6g(ap):
31    # For now, make sure the last operating channel was on 6 GHz band to get
32    # sufficient survey data from mac80211_hwsim.
33    ssid = "eht_6ghz_sae"
34    passphrase = "12345678"
35    params = hostapd.he_wpa2_params(ssid=ssid, passphrase=passphrase)
36    params["hw_mode"] = "a"
37    params["ieee80211ax"] = "1"
38    params["ieee80211be"] = "1"
39    params["op_class"] = "131"
40    params["channel"] = "5"
41    params["he_oper_centr_freq_seg0_idx"] = "5"
42    params["eht_oper_centr_freq_seg0_idx"] = "5"
43    params["country_code"] = "CA"
44    hostapd.add_ap(ap, params)
45    time.sleep(0.1)
46    hostapd.remove_bss(ap)
47
48def wait_acs(hapd, return_after_acs=False):
49    ev = hapd.wait_event(["ACS-STARTED", "ACS-COMPLETED", "ACS-FAILED",
50                          "AP-ENABLED", "AP-DISABLED"], timeout=5)
51    if not ev:
52        raise Exception("ACS start timed out")
53    if "ACS-STARTED" not in ev:
54        raise Exception("Unexpected ACS event: " + ev)
55
56    state = hapd.get_status_field("state")
57    if state != "ACS":
58        raise Exception("Unexpected interface state %s (expected ACS)" % state)
59
60    ev = hapd.wait_event(["ACS-COMPLETED", "ACS-FAILED", "AP-ENABLED",
61                          "AP-DISABLED"], timeout=20)
62    if not ev:
63        raise Exception("ACS timed out")
64    if "ACS-COMPLETED" not in ev:
65        raise Exception("Unexpected ACS event: " + ev)
66
67    if return_after_acs:
68        return
69
70    ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
71    if not ev:
72        raise Exception("AP setup timed out")
73    if "AP-ENABLED" not in ev:
74        raise Exception("Unexpected ACS event: " + ev)
75
76    state = hapd.get_status_field("state")
77    if state != "ENABLED":
78        raise Exception("Unexpected interface state %s (expected ENABLED)" % state)
79
80def test_ap_acs(dev, apdev):
81    """Automatic channel selection"""
82    force_prev_ap_on_24g(apdev[0])
83    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
84    params['channel'] = '0'
85    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
86    wait_acs(hapd)
87
88    freq = hapd.get_status_field("freq")
89    if int(freq) < 2400:
90        raise Exception("Unexpected frequency")
91
92    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
93
94def test_ap_acs_chanlist(dev, apdev):
95    """Automatic channel selection with chanlist set"""
96    force_prev_ap_on_24g(apdev[0])
97    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
98    params['channel'] = '0'
99    params['chanlist'] = '1 6 11'
100    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
101    wait_acs(hapd)
102
103    freq = hapd.get_status_field("freq")
104    if int(freq) < 2400:
105        raise Exception("Unexpected frequency")
106
107    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
108
109def test_ap_acs_freqlist(dev, apdev):
110    """Automatic channel selection with freqlist set"""
111    run_ap_acs_freqlist(dev, apdev, [2412, 2437, 2462])
112
113def test_ap_acs_freqlist2(dev, apdev):
114    """Automatic channel selection with freqlist set"""
115    run_ap_acs_freqlist(dev, apdev, [2417, 2432, 2457])
116
117def run_ap_acs_freqlist(dev, apdev, freqlist):
118    force_prev_ap_on_24g(apdev[0])
119    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
120    params['channel'] = '0'
121    params['freqlist'] = ','.join([str(x) for x in freqlist])
122    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
123    wait_acs(hapd)
124
125    freq = int(hapd.get_status_field("freq"))
126    if freq not in freqlist:
127        raise Exception("Unexpected frequency: %d" % freq)
128
129    dev[0].connect("test-acs", psk="12345678", scan_freq=str(freq))
130
131def test_ap_acs_invalid_chanlist(dev, apdev):
132    """Automatic channel selection with invalid chanlist"""
133    force_prev_ap_on_24g(apdev[0])
134    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
135    params['channel'] = '0'
136    params['chanlist'] = '15-18'
137    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
138    res = hapd.request("ENABLE")
139    if "OK" in res:
140        raise Exception("ENABLE command succeeded unexpectedly")
141
142def test_ap_multi_bss_acs(dev, apdev):
143    """hostapd start with a multi-BSS configuration file using ACS"""
144    skip_with_fips(dev[0])
145    check_sae_capab(dev[2])
146    force_prev_ap_on_24g(apdev[0])
147
148    # start the actual test
149    hapd = hostapd.add_iface(apdev[0], 'multi-bss-acs.conf')
150    hapd.enable()
151    wait_acs(hapd)
152
153    freq = hapd.get_status_field("freq")
154    if int(freq) < 2400:
155        raise Exception("Unexpected frequency")
156
157    dev[0].connect("bss-1", key_mgmt="NONE", scan_freq=freq)
158    dev[1].connect("bss-2", psk="12345678", scan_freq=freq)
159    dev[2].set("sae_groups", "")
160    dev[2].connect("bss-3", key_mgmt="SAE", psk="qwertyuiop", scan_freq=freq)
161
162def test_ap_acs_40mhz(dev, apdev):
163    """Automatic channel selection for 40 MHz channel"""
164    run_ap_acs_40mhz(dev, apdev, '[HT40+]')
165
166def test_ap_acs_40mhz_he(dev, apdev):
167    """Automatic channel selection for 40 MHz channel (HE)"""
168    run_ap_acs_40mhz(dev, apdev, '[HT40+]', he=True, allow20=True)
169
170def test_ap_acs_40mhz_plus_or_minus(dev, apdev):
171    """Automatic channel selection for 40 MHz channel (plus or minus)"""
172    run_ap_acs_40mhz(dev, apdev, '[HT40+][HT40-]')
173
174def run_ap_acs_40mhz(dev, apdev, ht_capab, he=False, allow20=False):
175    clear_scan_cache(apdev[0])
176    force_prev_ap_on_24g(apdev[0])
177    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
178    params['channel'] = '0'
179    params['ht_capab'] = ht_capab
180    if he:
181        params['ieee80211ax'] = '1'
182        params['he_oper_chwidth'] = '0'
183    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
184    wait_acs(hapd)
185
186    freq = hapd.get_status_field("freq")
187    if int(freq) < 2400:
188        raise Exception("Unexpected frequency")
189    sec = hapd.get_status_field("secondary_channel")
190    if int(sec) == 0:
191        if allow20:
192            logger.info("Fallback to 20 MHz detected")
193        else:
194            raise Exception("Secondary channel not set")
195
196    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
197
198def test_ap_acs_40mhz_minus(dev, apdev):
199    """Automatic channel selection for HT40- channel"""
200    clear_scan_cache(apdev[0])
201    force_prev_ap_on_24g(apdev[0])
202    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
203    params['channel'] = '0'
204    params['ht_capab'] = '[HT40-]'
205    params['acs_num_scans'] = '1'
206    params['chanlist'] = '1 11'
207    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
208    wait_acs(hapd)
209
210    freq = hapd.get_status_field("freq")
211    if int(freq) < 2400:
212        raise Exception("Unexpected frequency")
213    sec = hapd.get_status_field("secondary_channel")
214    if int(sec) != -1:
215        raise Exception("Unexpected secondary_channel: " + sec)
216
217    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
218    sig = dev[0].request("SIGNAL_POLL").splitlines()
219    logger.info("SIGNAL_POLL: " + str(sig))
220    if "WIDTH=40 MHz" not in sig:
221        raise Exception("Station did not report 40 MHz bandwidth")
222
223def test_ap_acs_5ghz(dev, apdev):
224    """Automatic channel selection on 5 GHz"""
225    try:
226        hapd = None
227        force_prev_ap_on_5g(apdev[0])
228        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
229        params['hw_mode'] = 'a'
230        params['channel'] = '0'
231        params['country_code'] = 'US'
232        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
233        wait_acs(hapd)
234        freq = hapd.get_status_field("freq")
235        if int(freq) < 5000:
236            raise Exception("Unexpected frequency")
237
238        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
239        dev[0].wait_regdom(country_ie=True)
240    finally:
241        clear_regdom(hapd, dev)
242
243def test_ap_acs_5ghz_40mhz(dev, apdev):
244    """Automatic channel selection on 5 GHz for 40 MHz channel"""
245    try:
246        hapd = None
247        force_prev_ap_on_5g(apdev[0])
248        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
249        params['hw_mode'] = 'a'
250        params['channel'] = '0'
251        params['ht_capab'] = '[HT40+]'
252        params['country_code'] = 'US'
253        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
254        wait_acs(hapd)
255        freq = hapd.get_status_field("freq")
256        if int(freq) < 5000:
257            raise Exception("Unexpected frequency")
258
259        sec = hapd.get_status_field("secondary_channel")
260        if int(sec) == 0:
261            raise Exception("Secondary channel not set")
262
263        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
264        dev[0].wait_regdom(country_ie=True)
265    finally:
266        clear_regdom(hapd, dev)
267
268def test_ap_acs_vht(dev, apdev):
269    """Automatic channel selection for VHT"""
270    try:
271        hapd = None
272        force_prev_ap_on_5g(apdev[0])
273        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
274        params['hw_mode'] = 'a'
275        params['channel'] = '0'
276        params['ht_capab'] = '[HT40+]'
277        params['country_code'] = 'US'
278        params['ieee80211ac'] = '1'
279        params['vht_oper_chwidth'] = '1'
280        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
281        wait_acs(hapd)
282        freq = hapd.get_status_field("freq")
283        if int(freq) < 5000:
284            raise Exception("Unexpected frequency")
285
286        sec = hapd.get_status_field("secondary_channel")
287        if int(sec) == 0:
288            raise Exception("Secondary channel not set")
289
290        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
291        dev[0].wait_regdom(country_ie=True)
292    finally:
293        clear_regdom(hapd, dev)
294
295def test_ap_acs_vht40(dev, apdev):
296    """Automatic channel selection for VHT40"""
297    try:
298        hapd = None
299        force_prev_ap_on_5g(apdev[0])
300        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
301        params['hw_mode'] = 'a'
302        params['channel'] = '0'
303        params['ht_capab'] = '[HT40+]'
304        params['country_code'] = 'US'
305        params['ieee80211ac'] = '1'
306        params['vht_oper_chwidth'] = '0'
307        params['acs_num_scans'] = '1'
308        params['chanlist'] = '36 149'
309        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
310        wait_acs(hapd)
311        freq = hapd.get_status_field("freq")
312        if int(freq) < 5000:
313            raise Exception("Unexpected frequency")
314
315        sec = hapd.get_status_field("secondary_channel")
316        if int(sec) == 0:
317            raise Exception("Secondary channel not set")
318
319        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
320        dev[0].wait_regdom(country_ie=True)
321    finally:
322        clear_regdom(hapd, dev)
323
324def test_ap_acs_vht80p80(dev, apdev):
325    """Automatic channel selection for VHT 80+80"""
326    try:
327        hapd = None
328        force_prev_ap_on_5g(apdev[0])
329        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
330        params['hw_mode'] = 'a'
331        params['channel'] = '0'
332        params['ht_capab'] = '[HT40+]'
333        params['country_code'] = 'US'
334        params['ieee80211ac'] = '1'
335        params['vht_oper_chwidth'] = '3'
336        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
337        ev = hapd.wait_event(["ACS-COMPLETED"], timeout=20)
338        if ev is None:
339            raise Exception("ACS did not complete")
340        # ACS for 80+80 is not yet supported, so the AP setup itself will fail.
341        # Do not try to connection before this gets fully supported.
342        ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
343        if ev is None:
344            raise Exception("AP enabled/disabled not reported")
345    finally:
346        clear_regdom(hapd, dev)
347
348def test_ap_acs_vht160(dev, apdev):
349    """Automatic channel selection for VHT160"""
350    try:
351        hapd = None
352        force_prev_ap_on_5g(apdev[0], country="ZA")
353        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
354        params['hw_mode'] = 'a'
355        params['channel'] = '0'
356        params['ht_capab'] = '[HT40+]'
357        params["vht_capab"] = "[VHT160]"
358        params['country_code'] = 'ZA'
359        params['ieee80211ac'] = '1'
360        params['vht_oper_chwidth'] = '2'
361        params['ieee80211d'] = '1'
362        params['ieee80211h'] = '1'
363        params['chanlist'] = '100'
364        params['acs_num_scans'] = '1'
365        hapd = hostapd.add_ap(apdev[0], params)
366        freq = hapd.get_status_field("freq")
367        if int(freq) < 5000:
368            raise Exception("Unexpected frequency")
369        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
370        dev[0].wait_regdom(country_ie=True)
371        hapd.wait_sta()
372        sig = dev[0].request("SIGNAL_POLL").splitlines()
373        logger.info("SIGNAL_POLL: " + str(sig))
374        if "WIDTH=160 MHz" not in sig:
375            raise Exception("Station did not report 160 MHz bandwidth")
376        dev[0].request("DISCONNECT")
377        dev[0].wait_disconnected()
378        hapd.wait_sta_disconnect()
379    finally:
380        clear_regdom(hapd, dev)
381
382def test_ap_acs_vht160_scan_disable(dev, apdev):
383    """Automatic channel selection for VHT160 and DISABLE during scan"""
384    force_prev_ap_on_5g(apdev[0], country="ZA")
385    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
386    params['hw_mode'] = 'a'
387    params['channel'] = '0'
388    params['ht_capab'] = '[HT40+]'
389    params['country_code'] = 'ZA'
390    params['ieee80211ac'] = '1'
391    params['vht_oper_chwidth'] = '2'
392    params["vht_oper_centr_freq_seg0_idx"] = "114"
393    params['ieee80211d'] = '1'
394    params['ieee80211h'] = '1'
395    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
396    time.sleep(3)
397    clear_regdom(hapd, dev)
398
399def test_ap_acs_bias(dev, apdev):
400    """Automatic channel selection with bias values"""
401    force_prev_ap_on_24g(apdev[0])
402    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
403    params['channel'] = '0'
404    params['acs_chan_bias'] = '1:0.8 3:1.2 6:0.7 11:0.8'
405    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
406    wait_acs(hapd)
407
408    freq = hapd.get_status_field("freq")
409    if int(freq) < 2400:
410        raise Exception("Unexpected frequency")
411
412    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
413
414def test_ap_acs_survey(dev, apdev):
415    """Automatic channel selection using acs_survey parameter"""
416    force_prev_ap_on_24g(apdev[0])
417    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
418    params['channel'] = 'acs_survey'
419    params['acs_num_scans'] = '1'
420    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
421    wait_acs(hapd)
422
423    freq = hapd.get_status_field("freq")
424    if int(freq) < 2400:
425        raise Exception("Unexpected frequency")
426
427    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
428
429def test_ap_acs_errors(dev, apdev):
430    """Automatic channel selection failures"""
431    clear_scan_cache(apdev[0])
432    force_prev_ap_on_24g(apdev[0])
433    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
434    params['channel'] = '0'
435    params['acs_num_scans'] = '2'
436    params['chanlist'] = '1'
437    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
438
439    with alloc_fail(hapd, 1, "acs_request_scan"):
440        if "FAIL" not in hapd.request("ENABLE"):
441            raise Exception("Unexpected success for ENABLE")
442
443    hapd.dump_monitor()
444    with fail_test(hapd, 1, "acs_request_scan"):
445        if "FAIL" not in hapd.request("ENABLE"):
446            raise Exception("Unexpected success for ENABLE")
447
448    hapd.dump_monitor()
449    with fail_test(hapd, 1, "acs_scan_complete"):
450        hapd.enable()
451        ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
452        if not ev:
453            raise Exception("ACS start timed out")
454
455    hapd.dump_monitor()
456    with fail_test(hapd, 1, "acs_request_scan;acs_scan_complete"):
457        hapd.enable()
458        ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
459        if not ev:
460            raise Exception("ACS start timed out")
461
462@long_duration_test
463def test_ap_acs_dfs(dev, apdev):
464    """Automatic channel selection, HT scan, and DFS"""
465    try:
466        hapd = None
467        force_prev_ap_on_5g(apdev[0])
468        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
469        params['hw_mode'] = 'a'
470        params['channel'] = '0'
471        params['ht_capab'] = '[HT40+]'
472        params['country_code'] = 'US'
473        params['ieee80211d'] = '1'
474        params['ieee80211h'] = '1'
475        params['acs_num_scans'] = '1'
476        params['chanlist'] = '52 56 60 64'
477        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
478        wait_acs(hapd, return_after_acs=True)
479
480        wait_dfs_event(hapd, "DFS-CAC-START", 5)
481        ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
482        if "success=1" not in ev:
483            raise Exception("CAC failed")
484
485        ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
486        if not ev:
487            raise Exception("AP setup timed out")
488
489        state = hapd.get_status_field("state")
490        if state != "ENABLED":
491            raise Exception("Unexpected interface state")
492
493        freq = int(hapd.get_status_field("freq"))
494        if freq not in [5260, 5280, 5300, 5320]:
495            raise Exception("Unexpected frequency: %d" % freq)
496
497        dev[0].connect("test-acs", psk="12345678", scan_freq=str(freq))
498        dev[0].wait_regdom(country_ie=True)
499    finally:
500        if hapd:
501            hapd.request("DISABLE")
502        dev[0].disconnect_and_stop_scan()
503        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
504        dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
505        dev[0].flush_scan_cache()
506
507def test_ap_acs_exclude_dfs(dev, apdev, params):
508    """Automatic channel selection, exclude DFS"""
509    try:
510        hapd = None
511        force_prev_ap_on_5g(apdev[0])
512        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
513        params['hw_mode'] = 'a'
514        params['channel'] = '0'
515        params['ht_capab'] = '[HT40+]'
516        params['country_code'] = 'US'
517        params['ieee80211d'] = '1'
518        params['ieee80211h'] = '1'
519        params['acs_num_scans'] = '1'
520        params['acs_exclude_dfs'] = '1'
521        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
522        wait_acs(hapd)
523
524        state = hapd.get_status_field("state")
525        if state != "ENABLED":
526            raise Exception("Unexpected interface state")
527
528        freq = int(hapd.get_status_field("freq"))
529        if freq in [5260, 5280, 5300, 5320,
530                    5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680]:
531            raise Exception("Unexpected frequency: %d" % freq)
532
533        dev[0].connect("test-acs", psk="12345678", scan_freq=str(freq))
534        dev[0].wait_regdom(country_ie=True)
535    finally:
536        if hapd:
537            hapd.request("DISABLE")
538        dev[0].disconnect_and_stop_scan()
539        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
540        dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
541        dev[0].flush_scan_cache()
542
543@long_duration_test
544def test_ap_acs_vht160_dfs(dev, apdev):
545    """Automatic channel selection 160 MHz, HT scan, and DFS"""
546    try:
547        hapd = None
548        force_prev_ap_on_5g(apdev[0])
549        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
550        params['hw_mode'] = 'a'
551        params['channel'] = '0'
552        params['ht_capab'] = '[HT40+]'
553        params['country_code'] = 'US'
554        params['ieee80211ac'] = '1'
555        params['vht_oper_chwidth'] = '2'
556        params['ieee80211d'] = '1'
557        params['ieee80211h'] = '1'
558        params['acs_num_scans'] = '1'
559        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
560        wait_acs(hapd, return_after_acs=True)
561
562        wait_dfs_event(hapd, "DFS-CAC-START", 5)
563        ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
564        if "success=1" not in ev:
565            raise Exception("CAC failed")
566
567        ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
568        if not ev:
569            raise Exception("AP setup timed out")
570
571        state = hapd.get_status_field("state")
572        if state != "ENABLED":
573            raise Exception("Unexpected interface state")
574
575        freq = int(hapd.get_status_field("freq"))
576        if freq not in [5180, 5500]:
577            raise Exception("Unexpected frequency: %d" % freq)
578
579        dev[0].connect("test-acs", psk="12345678", scan_freq=str(freq))
580        dev[0].wait_regdom(country_ie=True)
581    finally:
582        if hapd:
583            hapd.request("DISABLE")
584        dev[0].disconnect_and_stop_scan()
585        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
586        dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
587        dev[0].flush_scan_cache()
588
589def test_ap_acs_hw_mode_any(dev, apdev):
590    """Automatic channel selection with hw_mode=any"""
591    force_prev_ap_on_24g(apdev[0])
592    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
593    params['channel'] = '0'
594    params['hw_mode'] = 'any'
595    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
596    wait_acs(hapd)
597
598    freq = hapd.get_status_field("freq")
599    if int(freq) < 2400:
600        raise Exception("Unexpected frequency")
601
602    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
603
604def test_ap_acs_hw_mode_any_5ghz(dev, apdev):
605    """Automatic channel selection with hw_mode=any and 5 GHz"""
606    try:
607        hapd = None
608        force_prev_ap_on_5g(apdev[0])
609        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
610        params['hw_mode'] = 'any'
611        params['channel'] = '0'
612        params['country_code'] = 'US'
613        params['acs_chan_bias'] = '36:0.7 40:0.7 44:0.7 48:0.7'
614        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
615        wait_acs(hapd)
616        freq = hapd.get_status_field("freq")
617        if int(freq) < 5000:
618            raise Exception("Unexpected frequency")
619
620        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
621        dev[0].wait_regdom(country_ie=True)
622    finally:
623        clear_regdom(hapd, dev)
624
625def test_ap_acs_with_fallback_to_20(dev, apdev):
626    """Automatic channel selection with fallback to 20 MHz"""
627    force_prev_ap_on_24g(apdev[0])
628    params = {"ssid": "legacy-20",
629              "channel": "7", "ieee80211n": "0"}
630    hostapd.add_ap(apdev[1], params)
631    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
632    params['channel'] = '0'
633    params['acs_chan_bias'] = '6:0.1'
634    params['ht_capab'] = '[HT40+]'
635    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
636    wait_acs(hapd)
637
638    freq = hapd.get_status_field("freq")
639    if int(freq) < 2400:
640        raise Exception("Unexpected frequency")
641
642    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
643    sig = dev[0].request("SIGNAL_POLL").splitlines()
644    logger.info("SIGNAL_POLL: " + str(sig))
645    if "WIDTH=20 MHz" not in sig:
646        raise Exception("Station did not report 20 MHz bandwidth")
647
648def test_ap_acs_rx_during(dev, apdev):
649    """Automatic channel selection and RX during ACS"""
650    force_prev_ap_on_24g(apdev[0])
651    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
652    params['channel'] = '0'
653    params['chanlist'] = '1 6 11'
654    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
655
656    time.sleep(0.1)
657    hapd.set("ext_mgmt_frame_handling", "1")
658    bssid = hapd.own_addr().replace(':', '')
659    addr = "020304050607"
660    broadcast = 6*"ff"
661
662    probereq = "40000000" + broadcast + addr + broadcast + "1000"
663    probereq += "0000" + "010802040b160c121824" + "32043048606c" + "030100"
664    if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % probereq):
665        raise Exception("MGMT_RX_PROCESS failed")
666
667    probereq = "40000000" + broadcast + addr + broadcast + "1000"
668    probereq += "0000" + "010102"
669    if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2437 datarate=0 ssi_signal=-30 frame=%s" % probereq):
670        raise Exception("MGMT_RX_PROCESS failed")
671
672    auth = "b0003a01" + bssid + addr + bssid + '1000000001000000'
673    if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % auth):
674        raise Exception("MGMT_RX_PROCESS failed")
675    hapd.set("ext_mgmt_frame_handling", "0")
676
677    time.sleep(0.2)
678    try:
679        for i in range(3):
680            dev[i].request("SCAN_INTERVAL 1")
681            dev[i].connect("test-acs", psk="12345678",
682                           scan_freq="2412 2437 2462", wait_connect=False)
683        wait_acs(hapd)
684        for i in range(3):
685            dev[i].wait_connected()
686    finally:
687        for i in range(3):
688            dev[i].request("SCAN_INTERVAL 5")
689
690def test_ap_acs_he_24g(dev, apdev):
691    """Automatic channel selection on 2.4 GHz with HE"""
692    clear_scan_cache(apdev[0])
693    force_prev_ap_on_24g(apdev[0])
694
695    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
696    params['channel'] = '0'
697    params['ieee80211ax'] = '1'
698    params['ht_capab'] = '[HT40+]'
699    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
700    wait_acs(hapd)
701
702    freq = hapd.get_status_field("freq")
703    if int(freq) < 2400:
704        raise Exception("Unexpected frequency")
705
706    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
707
708def test_ap_acs_he_24g_overlap(dev, apdev):
709    """Automatic channel selection on 2.4 GHz with HE (overlap)"""
710    clear_scan_cache(apdev[0])
711    force_prev_ap_on_24g(apdev[0])
712
713    params = {"ssid": "overlapping",
714              "channel": "6", "ieee80211n": "1"}
715    hostapd.add_ap(apdev[1], params)
716
717    params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
718    params['channel'] = '0'
719    params['ieee80211ax'] = '1'
720    params['ht_capab'] = '[HT40+]'
721    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
722    wait_acs(hapd)
723
724    freq = hapd.get_status_field("freq")
725    if int(freq) < 2400:
726        raise Exception("Unexpected frequency")
727
728    dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
729
730def test_ap_acs_chan14(dev, apdev):
731    """Automatic channel selection and 2.4 GHz channel 14"""
732    try:
733        hapd = None
734        force_prev_ap_on_24g(apdev[0])
735        params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
736        params['hw_mode'] = 'g'
737        params['channel'] = '0'
738        params['country_code'] = 'JP'
739        params['acs_chan_bias'] = '14:0.01'
740        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
741        wait_acs(hapd)
742        freq = hapd.get_status_field("freq")
743        if int(freq) != 2484:
744            raise Exception("Unexpected frequency: " + str(freq))
745        if hapd.get_status_field("ieee80211n") != "0":
746            raise Exception("HT enabled unexpectedly")
747
748        dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
749        dev[0].wait_regdom(country_ie=True)
750    finally:
751        clear_regdom(hapd, dev)
752
753def test_ap_acs_eht320(dev, apdev):
754    """Automatic channel selection for EHT320 (offset 0)"""
755    run_ap_acs_eht320(dev, apdev, 0)
756
757def test_ap_acs_eht320_1(dev, apdev):
758    """Automatic channel selection for EHT320 (offset 1)"""
759    run_ap_acs_eht320(dev, apdev, 1)
760
761def test_ap_acs_eht320_2(dev, apdev):
762    """Automatic channel selection for EHT320 (offset 2)"""
763    run_ap_acs_eht320(dev, apdev, 2)
764
765def run_ap_acs_eht320(dev, apdev, bw32_offset):
766    check_sae_capab(dev[0])
767    try:
768        hapd = None
769        force_prev_ap_on_6g(apdev[0])
770        params = hostapd.he_wpa2_params(ssid="test-acs", passphrase="12345678")
771        params['hw_mode'] = 'a'
772        params["ieee80211ax"] = "1"
773        params["ieee80211be"] = "1"
774        params['channel'] = '0'
775        params['op_class'] = '137'
776        params['eht_bw320_offset'] = str(bw32_offset)
777        params['ieee80211w'] = '2'
778        params['country_code'] = 'CA'
779        params['acs_num_scans'] = '1'
780        params['ieee80211w'] = '2'
781        params['wpa_key_mgmt'] = 'SAE-EXT-KEY'
782        hapd = hostapd.add_ap(apdev[0], params)
783        freq = hapd.get_status_field("freq")
784        if int(freq) < 5900:
785            raise Exception("Unexpected frequency")
786        dev[0].set("sae_groups", "")
787        dev[0].connect("test-acs", psk="12345678", key_mgmt="SAE-EXT-KEY",
788                       ieee80211w="2", scan_freq=freq)
789        hapd.wait_sta()
790        dev[0].wait_regdom(country_ie=True)
791        sig = dev[0].request("SIGNAL_POLL").splitlines()
792        logger.info("SIGNAL_POLL: " + str(sig))
793        if "WIDTH=320 MHz" not in sig:
794            raise Exception("Station did not report 320 MHz bandwidth")
795        seg0 = int(hapd.get_status_field("eht_oper_centr_freq_seg0_idx"))
796        offset = int(hapd.get_status_field("eht_bw320_offset"))
797        chan_1 = [31, 95, 159]
798        chan_2 = [63, 127, 191]
799        if bw32_offset == 0:
800            if offset != 1 and offset != 2:
801                raise Exception("Unexpected eht_bw320_offset: %d" % offset)
802            if seg0 not in chan_1 and seg0 not in chan_2:
803                raise Exception("Unexpected seg0: %d" % seg0)
804        if bw32_offset == 1:
805            if offset != 1:
806                raise Exception("Unexpected eht_bw320_offset: %d" % offset)
807            if seg0 not in chan_1:
808                raise Exception("Unexpected seg0: %d" % seg0)
809        if bw32_offset == 2:
810            if offset != 2:
811                raise Exception("Unexpected eht_bw320_offset: %d" % offset)
812            if seg0 not in chan_2:
813                raise Exception("Unexpected seg0: %d" % seg0)
814
815        dev[0].request("DISCONNECT")
816        dev[0].wait_disconnected()
817        hapd.wait_sta_disconnect()
818    finally:
819        clear_regdom(hapd, dev)
820