1# Scanning tests
2# Copyright (c) 2013-2016, 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
7from remotehost import remote_compatible
8import binascii
9import time
10import logging
11logger = logging.getLogger()
12import os
13import struct
14import subprocess
15
16import hostapd
17from wpasupplicant import WpaSupplicant
18from utils import *
19from tshark import run_tshark
20from test_ap_csa import switch_channel, wait_channel_switch
21
22def check_scan(dev, params, other_started=False, test_busy=False):
23    if other_started:
24        ev = dev.wait_event(["CTRL-EVENT-SCAN-STARTED"])
25        if ev is None:
26            raise Exception("Other scan did not start")
27        if "id=" in ev:
28            raise Exception("Scan id unexpectedly included in start event")
29
30    if not other_started:
31        dev.dump_monitor()
32    id = dev.request("SCAN " + params)
33    if "FAIL" in id:
34        raise Exception("Failed to start scan")
35    id = int(id)
36
37    if test_busy:
38        if "FAIL-BUSY" not in dev.request("SCAN"):
39            raise Exception("SCAN command while already scanning not rejected")
40
41    if other_started:
42        ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"])
43        if ev is None:
44            raise Exception("Other scan did not complete")
45        if "id=" + str(id) in ev:
46            raise Exception("Own scan id unexpectedly included in completed event")
47
48    ev = dev.wait_event(["CTRL-EVENT-SCAN-STARTED"])
49    if ev is None:
50        raise Exception("Scan did not start")
51    if "id=" + str(id) not in ev:
52        raise Exception("Scan id not included in start event")
53    if test_busy:
54        if "FAIL-BUSY" not in dev.request("SCAN"):
55            raise Exception("SCAN command while already scanning not rejected")
56
57    ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"])
58    if ev is None:
59        raise Exception("Scan did not complete")
60    if "id=" + str(id) not in ev:
61        raise Exception("Scan id not included in completed event")
62
63def check_scan_retry(dev, params, bssid):
64    for i in range(0, 5):
65        check_scan(dev, "freq=2412-2462,5180 use_id=1")
66        if int(dev.get_bss(bssid)['age']) <= 1:
67            return
68    raise Exception("Unexpectedly old BSS entry")
69
70@remote_compatible
71def test_scan(dev, apdev):
72    """Control interface behavior on scan parameters"""
73    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
74    bssid = apdev[0]['bssid']
75
76    logger.info("Full scan")
77    check_scan(dev[0], "use_id=1", test_busy=True)
78
79    logger.info("Limited channel scan")
80    check_scan_retry(dev[0], "freq=2412-2462,5180 use_id=1", bssid)
81
82    # wait long enough to allow next scans to be verified not to find the AP
83    time.sleep(2)
84
85    logger.info("Passive single-channel scan")
86    check_scan(dev[0], "freq=2457 passive=1 use_id=1")
87    logger.info("Active single-channel scan")
88    check_scan(dev[0], "freq=2452 passive=0 use_id=1")
89    if int(dev[0].get_bss(bssid)['age']) < 2:
90        raise Exception("Unexpectedly updated BSS entry")
91
92    logger.info("Active single-channel scan on AP's operating channel")
93    check_scan_retry(dev[0], "freq=2412 passive=0 use_id=1", bssid)
94
95    logger.info("Disable collocated 6 GHz scanning")
96    check_scan(dev[0], "freq=2457 non_coloc_6ghz=1 use_id=1")
97
98@remote_compatible
99def test_scan_tsf(dev, apdev):
100    """Scan and TSF updates from Beacon/Probe Response frames"""
101    hostapd.add_ap(apdev[0], {"ssid": "test-scan",
102                              'beacon_int': "100"})
103    bssid = apdev[0]['bssid']
104
105    tsf = []
106    for passive in [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]:
107        check_scan(dev[0], "freq=2412 passive=%d use_id=1" % passive)
108        bss = dev[0].get_bss(bssid)
109        if bss:
110            tsf.append(int(bss['tsf']))
111            logger.info("TSF: " + bss['tsf'])
112    if tsf[-3] <= tsf[-4]:
113        # For now, only write this in the log without failing the test case
114        # since mac80211_hwsim does not yet update the Timestamp field in
115        # Probe Response frames.
116        logger.info("Probe Response did not update TSF")
117        #raise Exception("Probe Response did not update TSF")
118    if tsf[-1] <= tsf[-3]:
119        raise Exception("Beacon did not update TSF")
120    if 0 in tsf:
121        raise Exception("0 TSF reported")
122
123@remote_compatible
124def test_scan_only(dev, apdev):
125    """Control interface behavior on scan parameters with type=only"""
126    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
127    bssid = apdev[0]['bssid']
128
129    logger.info("Full scan")
130    check_scan(dev[0], "type=only use_id=1")
131
132    logger.info("Limited channel scan")
133    check_scan_retry(dev[0], "type=only freq=2412-2462,5180 use_id=1", bssid)
134
135    # wait long enough to allow next scans to be verified not to find the AP
136    time.sleep(2)
137
138    logger.info("Passive single-channel scan")
139    check_scan(dev[0], "type=only freq=2457 passive=1 use_id=1")
140    logger.info("Active single-channel scan")
141    check_scan(dev[0], "type=only freq=2452 passive=0 use_id=1")
142    if int(dev[0].get_bss(bssid)['age']) < 2:
143        raise Exception("Unexpectedly updated BSS entry")
144
145    logger.info("Active single-channel scan on AP's operating channel")
146    check_scan_retry(dev[0], "type=only freq=2412 passive=0 use_id=1", bssid)
147
148@remote_compatible
149def test_scan_external_trigger(dev, apdev):
150    """Avoid operations during externally triggered scan"""
151    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
152    bssid = apdev[0]['bssid']
153    dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger'])
154    check_scan(dev[0], "use_id=1", other_started=True)
155
156def test_scan_bss_expiration_count(dev, apdev):
157    """BSS entry expiration based on scan results without match"""
158    if "FAIL" not in dev[0].request("BSS_EXPIRE_COUNT 0"):
159        raise Exception("Invalid BSS_EXPIRE_COUNT accepted")
160    if "OK" not in dev[0].request("BSS_EXPIRE_COUNT 2"):
161        raise Exception("BSS_EXPIRE_COUNT failed")
162    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
163    bssid = apdev[0]['bssid']
164    dev[0].scan(freq="2412", only_new=True)
165    if bssid not in dev[0].request("SCAN_RESULTS"):
166        raise Exception("BSS not found in initial scan")
167    hapd.request("DISABLE")
168    # Try to give enough time for hostapd to have stopped mac80211 from
169    # beaconing before checking a new scan. This is needed with UML time travel
170    # testing.
171    hapd.ping()
172    time.sleep(0.2)
173    dev[0].scan(freq="2412", only_new=True)
174    if bssid not in dev[0].request("SCAN_RESULTS"):
175        raise Exception("BSS not found in first scan without match")
176    dev[0].scan(freq="2412", only_new=True)
177    if bssid in dev[0].request("SCAN_RESULTS"):
178        raise Exception("BSS found after two scans without match")
179
180@remote_compatible
181def test_scan_bss_expiration_age(dev, apdev):
182    """BSS entry expiration based on age"""
183    try:
184        if "FAIL" not in dev[0].request("BSS_EXPIRE_AGE COUNT 9"):
185            raise Exception("Invalid BSS_EXPIRE_AGE accepted")
186        if "OK" not in dev[0].request("BSS_EXPIRE_AGE 10"):
187            raise Exception("BSS_EXPIRE_AGE failed")
188        hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
189        bssid = apdev[0]['bssid']
190        # Allow couple more retries to avoid reporting errors during heavy load
191        for i in range(5):
192            dev[0].scan(freq="2412")
193            if bssid in dev[0].request("SCAN_RESULTS"):
194                break
195        if bssid not in dev[0].request("SCAN_RESULTS"):
196            raise Exception("BSS not found in initial scan")
197        hapd.request("DISABLE")
198        logger.info("Waiting for BSS entry to expire")
199        time.sleep(7)
200        if bssid not in dev[0].request("SCAN_RESULTS"):
201            raise Exception("BSS expired too quickly")
202        ev = dev[0].wait_event(["CTRL-EVENT-BSS-REMOVED"], timeout=15)
203        if ev is None:
204            raise Exception("BSS entry expiration timed out")
205        if bssid in dev[0].request("SCAN_RESULTS"):
206            raise Exception("BSS not removed after expiration time")
207    finally:
208        dev[0].request("BSS_EXPIRE_AGE 180")
209
210@remote_compatible
211def test_scan_filter(dev, apdev):
212    """Filter scan results based on SSID"""
213    try:
214        if "OK" not in dev[0].request("SET filter_ssids 1"):
215            raise Exception("SET failed")
216        id = dev[0].connect("test-scan", key_mgmt="NONE", only_add_network=True)
217        hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
218        bssid = apdev[0]['bssid']
219        hostapd.add_ap(apdev[1], {"ssid": "test-scan2"})
220        bssid2 = apdev[1]['bssid']
221        dev[0].scan(freq="2412", only_new=True)
222        if bssid not in dev[0].request("SCAN_RESULTS"):
223            raise Exception("BSS not found in scan results")
224        if bssid2 in dev[0].request("SCAN_RESULTS"):
225            raise Exception("Unexpected BSS found in scan results")
226        dev[0].set_network_quoted(id, "ssid", "")
227        dev[0].scan(freq="2412")
228        id2 = dev[0].connect("test", key_mgmt="NONE", only_add_network=True)
229        dev[0].scan(freq="2412")
230    finally:
231        dev[0].request("SET filter_ssids 0")
232
233@remote_compatible
234def test_scan_int(dev, apdev):
235    """scan interval configuration"""
236    try:
237        if "FAIL" not in dev[0].request("SCAN_INTERVAL -1"):
238            raise Exception("Accepted invalid scan interval")
239        if "OK" not in dev[0].request("SCAN_INTERVAL 1"):
240            raise Exception("Failed to set scan interval")
241        dev[0].connect("not-used", key_mgmt="NONE", scan_freq="2412",
242                       wait_connect=False)
243        times = {}
244        for i in range(0, 3):
245            logger.info("Waiting for scan to start")
246            start = os.times()[4]
247            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
248            if ev is None:
249                raise Exception("did not start a scan")
250            stop = os.times()[4]
251            times[i] = stop - start
252            logger.info("Waiting for scan to complete")
253            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 10)
254            if ev is None:
255                raise Exception("did not complete a scan")
256        logger.info("times=" + str(times))
257        if times[0] > 1 or times[1] < 0.5 or times[1] > 1.5 or times[2] < 0.5 or times[2] > 1.5:
258            raise Exception("Unexpected scan timing: " + str(times))
259    finally:
260        dev[0].request("SCAN_INTERVAL 5")
261
262def test_scan_bss_operations(dev, apdev):
263    """Control interface behavior on BSS parameters"""
264    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
265    bssid = apdev[0]['bssid']
266    hostapd.add_ap(apdev[1], {"ssid": "test2-scan"})
267    bssid2 = apdev[1]['bssid']
268
269    dev[0].flush_scan_cache()
270    dev[0].scan(freq="2412")
271    dev[0].scan(freq="2412")
272    dev[0].scan(freq="2412")
273
274    id1 = dev[0].request("BSS FIRST MASK=0x1").splitlines()[0].split('=')[1]
275    id2 = dev[0].request("BSS LAST MASK=0x1").splitlines()[0].split('=')[1]
276
277    res = dev[0].request("BSS RANGE=ALL MASK=0x20001")
278    if "id=" + id1 not in res:
279        raise Exception("Missing BSS " + id1)
280    if "id=" + id2 not in res:
281        raise Exception("Missing BSS " + id2)
282    if "====" not in res:
283        raise Exception("Missing delim")
284    if "####" not in res:
285        raise Exception("Missing end")
286
287    res = dev[0].request("BSS RANGE=ALL MASK=0")
288    if "id=" + id1 not in res:
289        raise Exception("Missing BSS " + id1)
290    if "id=" + id2 not in res:
291        raise Exception("Missing BSS " + id2)
292    if "====" in res:
293        raise Exception("Unexpected delim")
294    if "####" in res:
295        raise Exception("Unexpected end delim")
296
297    res = dev[0].request("BSS RANGE=ALL MASK=0x1").splitlines()
298    if len(res) != 2:
299        raise Exception("Unexpected result: " + str(res))
300    res = dev[0].request("BSS FIRST MASK=0x1")
301    if "id=" + id1 not in res:
302        raise Exception("Unexpected result: " + res)
303    res = dev[0].request("BSS LAST MASK=0x1")
304    if "id=" + id2 not in res:
305        raise Exception("Unexpected result: " + res)
306    res = dev[0].request("BSS ID-" + id1 + " MASK=0x1")
307    if "id=" + id1 not in res:
308        raise Exception("Unexpected result: " + res)
309    res = dev[0].request("BSS NEXT-" + id1 + " MASK=0x1")
310    if "id=" + id2 not in res:
311        raise Exception("Unexpected result: " + res)
312    res = dev[0].request("BSS NEXT-" + id2 + " MASK=0x1")
313    if "id=" in res:
314        raise Exception("Unexpected result: " + res)
315
316    if len(dev[0].request("BSS RANGE=" + id2 + " MASK=0x1").splitlines()) != 0:
317        raise Exception("Unexpected RANGE=1 result")
318    if len(dev[0].request("BSS RANGE=" + id1 + "- MASK=0x1").splitlines()) != 2:
319        raise Exception("Unexpected RANGE=0- result")
320    if len(dev[0].request("BSS RANGE=-" + id2 + " MASK=0x1").splitlines()) != 2:
321        raise Exception("Unexpected RANGE=-1 result")
322    if len(dev[0].request("BSS RANGE=" + id1 + "-" + id2 + " MASK=0x1").splitlines()) != 2:
323        raise Exception("Unexpected RANGE=0-1 result")
324    if len(dev[0].request("BSS RANGE=" + id2 + "-" + id2 + " MASK=0x1").splitlines()) != 1:
325        raise Exception("Unexpected RANGE=1-1 result")
326    if len(dev[0].request("BSS RANGE=" + str(int(id2) + 1) + "-" + str(int(id2) + 10) + " MASK=0x1").splitlines()) != 0:
327        raise Exception("Unexpected RANGE=2-10 result")
328    if len(dev[0].request("BSS RANGE=0-" + str(int(id2) + 10) + " MASK=0x1").splitlines()) != 2:
329        raise Exception("Unexpected RANGE=0-10 result")
330    if len(dev[0].request("BSS RANGE=" + id1 + "-" + id1 + " MASK=0x1").splitlines()) != 1:
331        raise Exception("Unexpected RANGE=0-0 result")
332
333    res = dev[0].request("BSS p2p_dev_addr=FOO")
334    if "FAIL" in res or "id=" in res:
335        raise Exception("Unexpected result: " + res)
336    res = dev[0].request("BSS p2p_dev_addr=00:11:22:33:44:55")
337    if "FAIL" in res or "id=" in res:
338        raise Exception("Unexpected result: " + res)
339
340    dev[0].request("BSS_FLUSH 1000")
341    res = dev[0].request("BSS RANGE=ALL MASK=0x1").splitlines()
342    if len(res) != 2:
343        raise Exception("Unexpected result after BSS_FLUSH 1000")
344    dev[0].request("BSS_FLUSH 0")
345    res = dev[0].request("BSS RANGE=ALL MASK=0x1").splitlines()
346    if len(res) != 0:
347        raise Exception("Unexpected result after BSS_FLUSH 0")
348
349@remote_compatible
350def test_scan_and_interface_disabled(dev, apdev):
351    """Scan operation when interface gets disabled"""
352    try:
353        dev[0].request("SCAN")
354        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
355        if ev is None:
356            raise Exception("Scan did not start")
357        dev[0].request("DRIVER_EVENT INTERFACE_DISABLED")
358        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=7)
359        if ev is not None:
360            raise Exception("Scan completed unexpectedly")
361
362        # verify that scan is rejected
363        if "FAIL" not in dev[0].request("SCAN"):
364            raise Exception("New scan request was accepted unexpectedly")
365
366        dev[0].request("DRIVER_EVENT INTERFACE_ENABLED")
367        dev[0].scan(freq="2412")
368    finally:
369        dev[0].request("DRIVER_EVENT INTERFACE_ENABLED")
370
371@remote_compatible
372def test_scan_for_auth(dev, apdev):
373    """cfg80211 workaround with scan-for-auth"""
374    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
375    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
376    # Block sme-connect radio work with an external radio work item, so that
377    # SELECT_NETWORK can decide to use fast associate without a new scan while
378    # cfg80211 still has the matching BSS entry, but the actual connection is
379    # not yet started.
380    id = dev[0].request("RADIO_WORK add block-work")
381    ev = dev[0].wait_event(["EXT-RADIO-WORK-START"])
382    if ev is None:
383        raise Exception("Timeout while waiting radio work to start")
384    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
385                   wait_connect=False)
386    dev[0].dump_monitor()
387    # Clear cfg80211 BSS table.
388    res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger',
389                                    'freq', '2457', 'flush'])
390    if res != 0:
391        raise HwsimSkip("iw scan trigger flush not supported")
392    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
393    if ev is None:
394        raise Exception("External flush scan timed out")
395    # Release blocking radio work to allow connection to go through with the
396    # cfg80211 BSS entry missing.
397    dev[0].request("RADIO_WORK done " + id)
398
399    dev[0].wait_connected(timeout=15)
400
401@remote_compatible
402def test_scan_for_auth_fail(dev, apdev):
403    """cfg80211 workaround with scan-for-auth failing"""
404    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
405    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
406    # Block sme-connect radio work with an external radio work item, so that
407    # SELECT_NETWORK can decide to use fast associate without a new scan while
408    # cfg80211 still has the matching BSS entry, but the actual connection is
409    # not yet started.
410    id = dev[0].request("RADIO_WORK add block-work")
411    ev = dev[0].wait_event(["EXT-RADIO-WORK-START"])
412    if ev is None:
413        raise Exception("Timeout while waiting radio work to start")
414    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
415                   wait_connect=False)
416    dev[0].dump_monitor()
417    hapd.disable()
418    # Clear cfg80211 BSS table.
419    res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger',
420                                    'freq', '2457', 'flush'])
421    if res != 0:
422        raise HwsimSkip("iw scan trigger flush not supported")
423    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
424    if ev is None:
425        raise Exception("External flush scan timed out")
426    # Release blocking radio work to allow connection to go through with the
427    # cfg80211 BSS entry missing.
428    dev[0].request("RADIO_WORK done " + id)
429
430    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS",
431                            "CTRL-EVENT-CONNECTED"], 15)
432    if ev is None:
433        raise Exception("Scan event missing")
434    if "CTRL-EVENT-CONNECTED" in ev:
435        raise Exception("Unexpected connection")
436    dev[0].request("DISCONNECT")
437
438@remote_compatible
439def test_scan_for_auth_wep(dev, apdev):
440    """cfg80211 scan-for-auth workaround with WEP keys"""
441    check_wep_capa(dev[0])
442    dev[0].flush_scan_cache()
443    hapd = hostapd.add_ap(apdev[0],
444                          {"ssid": "wep", "wep_key0": '"abcde"',
445                           "auth_algs": "2"})
446    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
447    # Block sme-connect radio work with an external radio work item, so that
448    # SELECT_NETWORK can decide to use fast associate without a new scan while
449    # cfg80211 still has the matching BSS entry, but the actual connection is
450    # not yet started.
451    id = dev[0].request("RADIO_WORK add block-work")
452    ev = dev[0].wait_event(["EXT-RADIO-WORK-START"])
453    if ev is None:
454        raise Exception("Timeout while waiting radio work to start")
455    dev[0].connect("wep", key_mgmt="NONE", wep_key0='"abcde"',
456                   auth_alg="SHARED", scan_freq="2412", wait_connect=False)
457    dev[0].dump_monitor()
458    # Clear cfg80211 BSS table.
459    res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger',
460                                    'freq', '2457', 'flush'])
461    if res != 0:
462        raise HwsimSkip("iw scan trigger flush not supported")
463    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
464    if ev is None:
465        raise Exception("External flush scan timed out")
466    # Release blocking radio work to allow connection to go through with the
467    # cfg80211 BSS entry missing.
468    dev[0].request("RADIO_WORK done " + id)
469
470    dev[0].wait_connected(timeout=15)
471
472@remote_compatible
473def test_scan_hidden(dev, apdev):
474    """Control interface behavior on scan parameters"""
475    dev[0].flush_scan_cache()
476    ssid = "test-scan"
477    wrong_ssid = "wrong"
478    hapd = hostapd.add_ap(apdev[0], {"ssid": ssid,
479                                     "ignore_broadcast_ssid": "1"})
480    bssid = apdev[0]['bssid']
481
482    check_scan(dev[0], "freq=2412 use_id=1")
483    try:
484        payload = struct.pack('BB', 0, len(wrong_ssid)) + wrong_ssid.encode()
485        ssid_list = struct.pack('BB', 84, len(payload)) + payload
486        cmd = "VENDOR_ELEM_ADD 14 " + binascii.hexlify(ssid_list).decode()
487        if "OK" not in dev[0].request(cmd):
488            raise Exception("VENDOR_ELEM_ADD failed")
489        check_scan(dev[0], "freq=2412 use_id=1")
490
491        payload = struct.pack('<L', binascii.crc32(wrong_ssid.encode()))
492        ssid_list = struct.pack('BBB', 255, 1 + len(payload), 58) + payload
493        cmd = "VENDOR_ELEM_ADD 14 " + binascii.hexlify(ssid_list).decode()
494        if "OK" not in dev[0].request(cmd):
495            raise Exception("VENDOR_ELEM_ADD failed")
496        check_scan(dev[0], "freq=2412 use_id=1")
497    finally:
498        dev[0].request("VENDOR_ELEM_REMOVE 14 *")
499    if "test-scan" in dev[0].request("SCAN_RESULTS"):
500        raise Exception("BSS unexpectedly found in initial scan")
501
502    id1 = dev[0].connect("foo", key_mgmt="NONE", scan_ssid="1",
503                         only_add_network=True)
504    id2 = dev[0].connect("test-scan", key_mgmt="NONE", scan_ssid="1",
505                         only_add_network=True)
506    id3 = dev[0].connect("bar", key_mgmt="NONE", only_add_network=True)
507
508    check_scan(dev[0], "freq=2412 use_id=1")
509    if "test-scan" in dev[0].request("SCAN_RESULTS"):
510        raise Exception("BSS unexpectedly found in scan")
511
512    # Allow multiple attempts to be more robust under heavy CPU load that can
513    # result in Probe Response frames getting sent only after the station has
514    # already stopped waiting for the response on the channel.
515    found = False
516    for i in range(10):
517        check_scan(dev[0], "scan_id=%d,%d,%d freq=2412 use_id=1" % (id1, id2, id3))
518        if "test-scan" in dev[0].request("SCAN_RESULTS"):
519            found = True
520            break
521    if not found:
522        raise Exception("BSS not found in scan")
523
524    if "FAIL" not in dev[0].request("SCAN scan_id=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17"):
525        raise Exception("Too many scan_id values accepted")
526
527    # Duplicate SSID removal
528    check_scan(dev[0], "scan_id=%d,%d,%d freq=2412 use_id=1" % (id1, id1, id2))
529
530    dev[0].request("REMOVE_NETWORK all")
531    hapd.disable()
532    dev[0].flush_scan_cache(freq=2432)
533    dev[0].flush_scan_cache()
534
535def test_scan_and_bss_entry_removed(dev, apdev):
536    """Last scan result and connect work processing on BSS entry update"""
537    hapd = hostapd.add_ap(apdev[0], {"ssid": "open",
538                                     "eap_server": "1",
539                                     "wps_state": "2"})
540    bssid = apdev[0]['bssid']
541
542    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
543    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
544
545    # Add a BSS entry
546    dev[0].scan_for_bss(bssid, freq="2412")
547    wpas.scan_for_bss(bssid, freq="2412")
548
549    # Start a connect radio work with a blocking entry preventing this from
550    # proceeding; this stores a pointer to the selected BSS entry.
551    id = dev[0].request("RADIO_WORK add block-work")
552    w_id = wpas.request("RADIO_WORK add block-work")
553    dev[0].wait_event(["EXT-RADIO-WORK-START"], timeout=1)
554    wpas.wait_event(["EXT-RADIO-WORK-START"], timeout=1)
555    nid = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
556                         wait_connect=False)
557    w_nid = wpas.connect("open", key_mgmt="NONE", scan_freq="2412",
558                         wait_connect=False)
559    time.sleep(0.1)
560
561    # Remove the BSS entry
562    dev[0].request("BSS_FLUSH 0")
563    wpas.request("BSS_FLUSH 0")
564
565    # Allow the connect radio work to continue. The bss entry stored in the
566    # pending connect work is now stale. This will result in the connection
567    # attempt failing since the BSS entry does not exist.
568    dev[0].request("RADIO_WORK done " + id)
569    wpas.request("RADIO_WORK done " + w_id)
570
571    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
572    if ev is not None:
573        raise Exception("Unexpected connection")
574    dev[0].remove_network(nid)
575    ev = wpas.wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
576    if ev is not None:
577        raise Exception("Unexpected connection")
578    wpas.remove_network(w_nid)
579    time.sleep(0.5)
580    dev[0].request("BSS_FLUSH 0")
581    wpas.request("BSS_FLUSH 0")
582
583    # Add a BSS entry
584    dev[0].scan_for_bss(bssid, freq="2412")
585    wpas.scan_for_bss(bssid, freq="2412")
586
587    # Start a connect radio work with a blocking entry preventing this from
588    # proceeding; this stores a pointer to the selected BSS entry.
589    id = dev[0].request("RADIO_WORK add block-work")
590    w_id = wpas.request("RADIO_WORK add block-work")
591    dev[0].wait_event(["EXT-RADIO-WORK-START"], timeout=1)
592    wpas.wait_event(["EXT-RADIO-WORK-START"], timeout=1)
593
594    # Schedule a connection based on the current BSS entry.
595    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
596                   wait_connect=False)
597    wpas.connect("open", key_mgmt="NONE", scan_freq="2412",
598                 wait_connect=False)
599
600    # Update scan results with results that have longer set of IEs so that new
601    # memory needs to be allocated for the BSS entry.
602    hapd.request("WPS_PBC")
603    time.sleep(0.1)
604    subprocess.call(['iw', dev[0].ifname, 'scan', 'trigger', 'freq', '2412'])
605    subprocess.call(['iw', wpas.ifname, 'scan', 'trigger', 'freq', '2412'])
606    time.sleep(0.1)
607
608    # Allow the connect radio work to continue. The bss entry stored in the
609    # pending connect work becomes stale during the scan and it must have been
610    # updated for the connection to work.
611    dev[0].request("RADIO_WORK done " + id)
612    wpas.request("RADIO_WORK done " + w_id)
613
614    dev[0].wait_connected(timeout=15, error="No connection (sme-connect)")
615    wpas.wait_connected(timeout=15, error="No connection (connect)")
616    dev[0].request("DISCONNECT")
617    wpas.request("DISCONNECT")
618    dev[0].flush_scan_cache()
619    wpas.flush_scan_cache()
620
621@remote_compatible
622def test_scan_reqs_with_non_scan_radio_work(dev, apdev):
623    """SCAN commands while non-scan radio_work is in progress"""
624    id = dev[0].request("RADIO_WORK add test-work-a")
625    ev = dev[0].wait_event(["EXT-RADIO-WORK-START"])
626    if ev is None:
627        raise Exception("Timeout while waiting radio work to start")
628
629    if "OK" not in dev[0].request("SCAN"):
630        raise Exception("SCAN failed")
631    if "FAIL-BUSY" not in dev[0].request("SCAN"):
632        raise Exception("SCAN accepted while one is already pending")
633    if "FAIL-BUSY" not in dev[0].request("SCAN"):
634        raise Exception("SCAN accepted while one is already pending")
635
636    res = dev[0].request("RADIO_WORK show").splitlines()
637    count = 0
638    for l in res:
639        if "scan" in l:
640            count += 1
641    if count != 1:
642        logger.info(res)
643        raise Exception("Unexpected number of scan radio work items")
644
645    dev[0].dump_monitor()
646    dev[0].request("RADIO_WORK done " + id)
647    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
648    if ev is None:
649        raise Exception("Scan did not start")
650    if "FAIL-BUSY" not in dev[0].request("SCAN"):
651        raise Exception("SCAN accepted while one is already in progress")
652
653    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
654    if ev is None:
655        raise Exception("Scan did not complete")
656    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.2)
657    if ev is not None:
658        raise Exception("Unexpected scan started")
659
660def test_scan_setband(dev, apdev):
661    """Band selection for scan operations"""
662    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
663    wpas.interface_add("wlan5")
664    devs = [ dev[0], dev[1], dev[2], wpas ]
665
666    try:
667        hapd = None
668        hapd2 = None
669        params = {"ssid": "test-setband",
670                  "hw_mode": "a",
671                  "channel": "36",
672                  "country_code": "US"}
673        hapd = hostapd.add_ap(apdev[0], params)
674        bssid = apdev[0]['bssid']
675
676        params = {"ssid": "test-setband",
677                  "hw_mode": "g",
678                  "channel": "1"}
679        hapd2 = hostapd.add_ap(apdev[1], params)
680        bssid2 = apdev[1]['bssid']
681
682        if "FAIL" not in dev[0].request("SET setband FOO"):
683            raise Exception("Invalid set setband accepted")
684        if "OK" not in dev[0].request("SET setband AUTO"):
685            raise Exception("Failed to set setband")
686        if "OK" not in dev[1].request("SET setband 5G"):
687            raise Exception("Failed to set setband")
688        if "OK" not in dev[2].request("SET setband 2G"):
689            raise Exception("Failed to set setband")
690        if "OK" not in wpas.request("SET setband 2G,5G"):
691            raise Exception("Failed to set setband")
692
693        # Allow a retry to avoid reporting errors during heavy load
694        for j in range(5):
695            for d in devs:
696                d.request("SCAN only_new=1")
697
698            for d in devs:
699                ev = d.wait_event(["CTRL-EVENT-SCAN-RESULTS"], 30)
700                if ev is None:
701                    raise Exception("Scan timed out")
702
703            res0 = dev[0].request("SCAN_RESULTS")
704            res1 = dev[1].request("SCAN_RESULTS")
705            res2 = dev[2].request("SCAN_RESULTS")
706            res3 = wpas.request("SCAN_RESULTS")
707            if bssid in res0 and bssid2 in res0 and \
708               bssid in res1 and bssid2 in res2 and \
709               bssid in res3 and bssid2 in res3:
710                break
711
712        res = dev[0].request("SCAN_RESULTS")
713        if bssid not in res or bssid2 not in res:
714            raise Exception("Missing scan result(0)")
715
716        res = dev[1].request("SCAN_RESULTS")
717        if bssid not in res:
718            raise Exception("Missing scan result(1)")
719        if bssid2 in res:
720            raise Exception("Unexpected scan result(1)")
721
722        res = dev[2].request("SCAN_RESULTS")
723        if bssid2 not in res:
724            raise Exception("Missing scan result(2)")
725        if bssid in res:
726            raise Exception("Unexpected scan result(2)")
727
728        res = wpas.request("SCAN_RESULTS")
729        if bssid not in res or bssid2 not in res:
730            raise Exception("Missing scan result(3)")
731    finally:
732        if hapd:
733            hapd.request("DISABLE")
734        if hapd2:
735            hapd2.request("DISABLE")
736        subprocess.call(['iw', 'reg', 'set', '00'])
737        for d in devs:
738            d.request("SET setband AUTO")
739            d.flush_scan_cache()
740
741@remote_compatible
742def test_scan_hidden_many(dev, apdev):
743    """scan_ssid=1 with large number of profile with hidden SSID"""
744    try:
745        _test_scan_hidden_many(dev, apdev)
746    finally:
747        dev[0].flush_scan_cache(freq=2432)
748        dev[0].flush_scan_cache()
749        dev[0].request("SCAN_INTERVAL 5")
750
751def _test_scan_hidden_many(dev, apdev):
752    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan-ssid",
753                                     "ignore_broadcast_ssid": "1"})
754    bssid = apdev[0]['bssid']
755
756    dev[0].request("SCAN_INTERVAL 1")
757
758    for i in range(5):
759        id = dev[0].add_network()
760        dev[0].set_network_quoted(id, "ssid", "foo")
761        dev[0].set_network(id, "key_mgmt", "NONE")
762        dev[0].set_network(id, "disabled", "0")
763        dev[0].set_network(id, "scan_freq", "2412")
764        dev[0].set_network(id, "scan_ssid", "1")
765
766    dev[0].set_network_quoted(id, "ssid", "test-scan-ssid")
767    dev[0].set_network(id, "key_mgmt", "NONE")
768    dev[0].set_network(id, "disabled", "0")
769    dev[0].set_network(id, "scan_freq", "2412")
770    dev[0].set_network(id, "scan_ssid", "1")
771
772    for i in range(5):
773        id = dev[0].add_network()
774        dev[0].set_network_quoted(id, "ssid", "foo")
775        dev[0].set_network(id, "key_mgmt", "NONE")
776        dev[0].set_network(id, "disabled", "0")
777        dev[0].set_network(id, "scan_freq", "2412")
778        dev[0].set_network(id, "scan_ssid", "1")
779
780    dev[0].request("REASSOCIATE")
781    dev[0].wait_connected(timeout=30)
782    dev[0].request("REMOVE_NETWORK all")
783    hapd.disable()
784
785def test_scan_random_mac(dev, apdev, params):
786    """Random MAC address in scans"""
787    try:
788        _test_scan_random_mac(dev, apdev, params)
789    finally:
790        dev[0].request("MAC_RAND_SCAN all enable=0")
791
792def _test_scan_random_mac(dev, apdev, params):
793    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
794    bssid = apdev[0]['bssid']
795
796    tests = ["",
797             "addr=foo",
798             "mask=foo",
799             "enable=1",
800             "all enable=1 mask=00:11:22:33:44:55",
801             "all enable=1 addr=00:11:22:33:44:55",
802             "all enable=1 addr=01:11:22:33:44:55 mask=ff:ff:ff:ff:ff:ff",
803             "all enable=1 addr=00:11:22:33:44:55 mask=fe:ff:ff:ff:ff:ff",
804             "enable=2 scan sched pno all",
805             "pno enable=1",
806             "all enable=2",
807             "foo"]
808    for args in tests:
809        if "FAIL" not in dev[0].request("MAC_RAND_SCAN " + args):
810            raise Exception("Invalid MAC_RAND_SCAN accepted: " + args)
811
812    if dev[0].get_driver_status_field('capa.mac_addr_rand_scan_supported') != '1':
813        raise HwsimSkip("Driver does not support random MAC address for scanning")
814
815    tests = ["all enable=1",
816             "all enable=1 addr=f2:11:22:33:44:55 mask=ff:ff:ff:ff:ff:ff",
817             "all enable=1 addr=f2:11:33:00:00:00 mask=ff:ff:ff:00:00:00"]
818    for args in tests:
819        dev[0].request("MAC_RAND_SCAN " + args)
820        dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
821
822    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
823                     "wlan.fc.type_subtype == 4", ["wlan.ta"])
824    if out is not None:
825        addr = out.splitlines()
826        logger.info("Probe Request frames seen from: " + str(addr))
827        if dev[0].own_addr() in addr:
828            raise Exception("Real address used to transmit Probe Request frame")
829        if "f2:11:22:33:44:55" not in addr:
830            raise Exception("Fully configured random address not seen")
831        found = False
832        for a in addr:
833            if a.startswith('f2:11:33'):
834                found = True
835                break
836        if not found:
837            raise Exception("Fixed OUI random address not seen")
838
839def test_scan_random_mac_connected(dev, apdev, params):
840    """Random MAC address in scans while connected"""
841    try:
842        _test_scan_random_mac_connected(dev, apdev, params)
843    finally:
844        dev[0].request("MAC_RAND_SCAN all enable=0")
845
846def _test_scan_random_mac_connected(dev, apdev, params):
847    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
848    bssid = apdev[0]['bssid']
849    if dev[0].get_driver_status_field('capa.mac_addr_rand_scan_supported') != '1':
850        raise HwsimSkip("Driver does not support random MAC address for scanning")
851
852    dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412")
853
854    hostapd.add_ap(apdev[1], {"ssid": "test-scan-2", "channel": "11"})
855    bssid1 = apdev[1]['bssid']
856
857    # Verify that scanning can be completed while connected even if that means
858    # disabling use of random MAC address.
859    dev[0].request("MAC_RAND_SCAN all enable=1")
860    dev[0].scan_for_bss(bssid1, freq=2462, force_scan=True)
861
862@remote_compatible
863def test_scan_trigger_failure(dev, apdev):
864    """Scan trigger to the driver failing"""
865    if dev[0].get_status_field('wpa_state') == "SCANNING":
866        raise Exception("wpa_state was already SCANNING")
867
868    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
869    bssid = apdev[0]['bssid']
870
871    if "OK" not in dev[0].request("SET test_failure 1"):
872        raise Exception("Failed to set test_failure")
873
874    if "OK" not in dev[0].request("SCAN"):
875        raise Exception("SCAN command failed")
876    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=10)
877    if ev is None:
878        raise Exception("Did not receive CTRL-EVENT-SCAN-FAILED event")
879    if "retry=1" in ev:
880        raise Exception("Unexpected scan retry indicated")
881    if dev[0].get_status_field('wpa_state') == "SCANNING":
882        raise Exception("wpa_state SCANNING not cleared")
883
884    id = dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412",
885                        only_add_network=True)
886    dev[0].select_network(id)
887    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=10)
888    if ev is None:
889        raise Exception("Did not receive CTRL-EVENT-SCAN-FAILED event")
890    if "retry=1" not in ev:
891        raise Exception("No scan retry indicated for connection")
892    if dev[0].get_status_field('wpa_state') == "SCANNING":
893        raise Exception("wpa_state SCANNING not cleared")
894    dev[0].request("SET test_failure 0")
895    dev[0].wait_connected()
896
897    dev[0].request("SET test_failure 1")
898    if "OK" not in dev[0].request("SCAN"):
899        raise Exception("SCAN command failed")
900    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=10)
901    if ev is None:
902        raise Exception("Did not receive CTRL-EVENT-SCAN-FAILED event")
903    if "retry=1" in ev:
904        raise Exception("Unexpected scan retry indicated")
905    if dev[0].get_status_field('wpa_state') != "COMPLETED":
906        raise Exception("wpa_state COMPLETED not restored")
907    dev[0].request("SET test_failure 0")
908
909@remote_compatible
910def test_scan_specify_ssid(dev, apdev):
911    """Control interface behavior on scan SSID parameter"""
912    dev[0].flush_scan_cache()
913    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-hidden",
914                                     "ignore_broadcast_ssid": "1"})
915    bssid = apdev[0]['bssid']
916    check_scan(dev[0], "freq=2412 use_id=1 ssid 414243")
917    bss = dev[0].get_bss(bssid)
918    if bss is not None and bss['ssid'] == 'test-hidden':
919        raise Exception("BSS entry for hidden AP present unexpectedly")
920    # Allow couple more retries to avoid reporting errors during heavy load
921    for i in range(5):
922        check_scan(dev[0], "freq=2412 ssid 414243 ssid 746573742d68696464656e ssid 616263313233 use_id=1")
923        bss = dev[0].get_bss(bssid)
924        if bss and 'test-hidden' in dev[0].request("SCAN_RESULTS"):
925            break
926    if bss is None:
927        raise Exception("BSS entry for hidden AP not found")
928    if 'test-hidden' not in dev[0].request("SCAN_RESULTS"):
929        raise Exception("Expected SSID not included in the scan results")
930
931    hapd.disable()
932    dev[0].flush_scan_cache(freq=2432)
933    dev[0].flush_scan_cache()
934
935    if "FAIL" not in dev[0].request("SCAN ssid foo"):
936        raise Exception("Invalid SCAN command accepted")
937
938@remote_compatible
939def test_scan_ap_scan_2_ap_mode(dev, apdev):
940    """AP_SCAN 2 AP mode and scan()"""
941    try:
942        _test_scan_ap_scan_2_ap_mode(dev, apdev)
943    finally:
944        dev[0].request("AP_SCAN 1")
945
946def _test_scan_ap_scan_2_ap_mode(dev, apdev):
947    if "OK" not in dev[0].request("AP_SCAN 2"):
948        raise Exception("Failed to set AP_SCAN 2")
949
950    id = dev[0].add_network()
951    dev[0].set_network(id, "mode", "2")
952    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
953    dev[0].set_network(id, "key_mgmt", "NONE")
954    dev[0].set_network(id, "frequency", "2412")
955    dev[0].set_network(id, "scan_freq", "2412")
956    dev[0].set_network(id, "disabled", "0")
957    dev[0].select_network(id)
958    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
959    if ev is None:
960        raise Exception("AP failed to start")
961
962    with fail_test(dev[0], 1, "wpa_driver_nl80211_scan"):
963        if "OK" not in dev[0].request("SCAN freq=2412"):
964            raise Exception("SCAN command failed unexpectedly")
965        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED",
966                                "AP-DISABLED"], timeout=5)
967        if ev is None:
968            raise Exception("CTRL-EVENT-SCAN-FAILED not seen")
969        if "AP-DISABLED" in ev:
970            raise Exception("Unexpected AP-DISABLED event")
971        if "retry=1" in ev:
972            # Wait for the retry to scan happen
973            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED",
974                                    "AP-DISABLED"], timeout=5)
975            if ev is None:
976                raise Exception("CTRL-EVENT-SCAN-FAILED not seen - retry")
977            if "AP-DISABLED" in ev:
978                raise Exception("Unexpected AP-DISABLED event - retry")
979
980    dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
981    dev[1].request("DISCONNECT")
982    dev[1].wait_disconnected()
983    dev[0].request("DISCONNECT")
984    dev[0].wait_disconnected()
985
986def test_scan_bss_expiration_on_ssid_change(dev, apdev):
987    """BSS entry expiration when AP changes SSID"""
988    dev[0].flush_scan_cache()
989    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
990    bssid = apdev[0]['bssid']
991    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
992
993    hapd.request("DISABLE")
994    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
995    if "OK" not in dev[0].request("BSS_EXPIRE_COUNT 3"):
996        raise Exception("BSS_EXPIRE_COUNT failed")
997    dev[0].scan(freq="2412")
998    dev[0].scan(freq="2412")
999    if "OK" not in dev[0].request("BSS_EXPIRE_COUNT 2"):
1000        raise Exception("BSS_EXPIRE_COUNT failed")
1001    res = dev[0].request("SCAN_RESULTS")
1002    if "test-scan" not in res:
1003        raise Exception("The first SSID not in scan results")
1004    if "open" not in res:
1005        raise Exception("The second SSID not in scan results")
1006    dev[0].connect("open", key_mgmt="NONE")
1007
1008    dev[0].request("BSS_FLUSH 0")
1009    res = dev[0].request("SCAN_RESULTS")
1010    if "test-scan" in res:
1011        raise Exception("The BSS entry with the old SSID was not removed")
1012    dev[0].request("DISCONNECT")
1013    dev[0].wait_disconnected()
1014
1015def test_scan_dfs(dev, apdev, params):
1016    """Scan on DFS channels"""
1017    try:
1018        _test_scan_dfs(dev, apdev, params)
1019    finally:
1020        clear_regdom_dev(dev)
1021
1022def _test_scan_dfs(dev, apdev, params):
1023    subprocess.call(['iw', 'reg', 'set', 'US'])
1024    for i in range(2):
1025        for j in range(5):
1026            ev = dev[i].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
1027            if ev is None:
1028                raise Exception("No regdom change event")
1029            if "alpha2=US" in ev:
1030                break
1031        dev[i].dump_monitor()
1032
1033    if "OK" not in dev[0].request("SCAN"):
1034        raise Exception("SCAN command failed")
1035    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=30)
1036    if ev is None:
1037        raise Exception("Scan did not complete")
1038
1039    if "OK" not in dev[0].request("SCAN freq=2412,5180,5260,5500,5600,5745"):
1040        raise Exception("SCAN command failed")
1041    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
1042    if ev is None:
1043        raise Exception("Scan did not complete")
1044
1045    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1046                     "wlan.fc.type_subtype == 4", ["radiotap.channel.freq"])
1047    if out is not None:
1048        freq = out.splitlines()
1049        freq = [int(f) for f in freq]
1050        freq = list(set(freq))
1051        freq.sort()
1052        logger.info("Active scan seen on channels: " + str(freq))
1053        for f in freq:
1054            if (f >= 5260 and f <= 5320) or (f >= 5500 and f <= 5700):
1055                raise Exception("Active scan on DFS channel: %d" % f)
1056            if f in [2467, 2472]:
1057                raise Exception("Active scan on US-disallowed channel: %d" % f)
1058
1059@remote_compatible
1060def test_scan_abort(dev, apdev):
1061    """Aborting a full scan"""
1062    dev[0].request("SCAN")
1063    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
1064    if ev is None:
1065        raise Exception("Scan did not start")
1066    if "OK" not in dev[0].request("ABORT_SCAN"):
1067        raise Exception("ABORT_SCAN command failed")
1068    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=2)
1069    if ev is None:
1070        raise Exception("Scan did not terminate")
1071
1072@remote_compatible
1073def test_scan_abort_on_connect(dev, apdev):
1074    """Aborting a full scan on connection request"""
1075    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1076    bssid = apdev[0]['bssid']
1077
1078    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
1079    dev[0].dump_monitor()
1080    dev[0].request("SCAN")
1081    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
1082    if ev is None:
1083        raise Exception("Scan did not start")
1084    dev[0].connect("test-scan", key_mgmt="NONE")
1085
1086@remote_compatible
1087def test_scan_ext(dev, apdev):
1088    """Custom IE in Probe Request frame"""
1089    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1090    bssid = apdev[0]['bssid']
1091
1092    try:
1093        if "OK" not in dev[0].request("VENDOR_ELEM_ADD 14 dd050011223300"):
1094            raise Exception("VENDOR_ELEM_ADD failed")
1095        check_scan(dev[0], "freq=2412 use_id=1")
1096    finally:
1097        dev[0].request("VENDOR_ELEM_REMOVE 14 *")
1098
1099def test_scan_fail(dev, apdev):
1100    """Scan failures"""
1101    with fail_test(dev[0], 1, "wpa_driver_nl80211_scan"):
1102        dev[0].request("DISCONNECT")
1103        if "OK" not in dev[0].request("SCAN freq=2412"):
1104            raise Exception("SCAN failed")
1105        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
1106        if ev is None:
1107            raise Exception("Did not see scan failure event")
1108    dev[0].dump_monitor()
1109
1110    for i in range(1, 5):
1111        with alloc_fail(dev[0], i,
1112                        "wpa_scan_clone_params;wpa_supplicant_trigger_scan"):
1113            if "OK" not in dev[0].request("SCAN ssid 112233 freq=2412"):
1114                raise Exception("SCAN failed")
1115            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
1116            if ev is None:
1117                raise Exception("Did not see scan failure event")
1118        dev[0].dump_monitor()
1119
1120    with alloc_fail(dev[0], 1, "radio_add_work;wpa_supplicant_trigger_scan"):
1121        if "OK" not in dev[0].request("SCAN freq=2412"):
1122            raise Exception("SCAN failed")
1123        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
1124        if ev is None:
1125            raise Exception("Did not see scan failure event")
1126    dev[0].dump_monitor()
1127
1128    try:
1129        if "OK" not in dev[0].request("SET filter_ssids 1"):
1130            raise Exception("SET failed")
1131        id = dev[0].connect("test-scan", key_mgmt="NONE", only_add_network=True)
1132        with alloc_fail(dev[0], 1, "wpa_supplicant_build_filter_ssids"):
1133            # While the filter list cannot be created due to memory allocation
1134            # failure, this scan is expected to be completed without SSID
1135            # filtering.
1136            if "OK" not in dev[0].request("SCAN freq=2412"):
1137                raise Exception("SCAN failed")
1138            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
1139            if ev is None:
1140                raise Exception("Scan did not complete")
1141        dev[0].remove_network(id)
1142    finally:
1143        dev[0].request("SET filter_ssids 0")
1144    dev[0].dump_monitor()
1145
1146    with alloc_fail(dev[0], 1, "nl80211_get_scan_results"):
1147        if "OK" not in dev[0].request("SCAN freq=2412"):
1148            raise Exception("SCAN failed")
1149        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
1150        if ev is None:
1151            raise Exception("Did not see scan started event")
1152        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1153    dev[0].dump_monitor()
1154
1155    try:
1156        if "OK" not in dev[0].request("SET setband 2G"):
1157            raise Exception("SET setband failed")
1158        with alloc_fail(dev[0], 1, "=wpa_add_scan_freqs_list"):
1159            # While the frequency list cannot be created due to memory
1160            # allocation failure, this scan is expected to be completed without
1161            # frequency filtering.
1162            if "OK" not in dev[0].request("SCAN"):
1163                raise Exception("SCAN failed")
1164            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1165            dev[0].request("ABORT_SCAN")
1166            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
1167            if ev is None:
1168                raise Exception("Scan did not complete")
1169    finally:
1170        dev[0].request("SET setband AUTO")
1171    dev[0].dump_monitor()
1172
1173    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1174    wpas.interface_add("wlan5")
1175    wpas.request("SET preassoc_mac_addr 1")
1176    with fail_test(wpas, 1, "nl80211_set_mac_addr;wpas_trigger_scan_cb"):
1177        if "OK" not in wpas.request("SCAN freq=2412"):
1178            raise Exception("SCAN failed")
1179        ev = wpas.wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
1180        if ev is None:
1181            raise Exception("Did not see scan failure event")
1182    wpas.request("SET preassoc_mac_addr 0")
1183    wpas.dump_monitor()
1184
1185    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
1186    with alloc_fail(dev[0], 1, "wpa_bss_add"):
1187        dev[0].flush_scan_cache()
1188        dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
1189
1190def test_scan_fail_type_only(dev, apdev):
1191    """Scan failures for TYPE=ONLY"""
1192    with fail_test(dev[0], 1, "wpa_driver_nl80211_scan"):
1193        dev[0].request("SCAN TYPE=ONLY freq=2417")
1194        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
1195        if ev is None:
1196            raise Exception("Scan trigger failure not reported")
1197    # Verify that scan_only_handler() does not get left set as the
1198    # wpa_s->scan_res_handler in failure case.
1199    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
1200    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
1201
1202@remote_compatible
1203def test_scan_freq_list(dev, apdev):
1204    """Scan with SET freq_list and scan_cur_freq"""
1205    try:
1206        if "OK" not in dev[0].request("SET freq_list 2412 2417"):
1207            raise Exception("SET freq_list failed")
1208        check_scan(dev[0], "use_id=1")
1209    finally:
1210        dev[0].request("SET freq_list ")
1211
1212    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1213    dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412")
1214    try:
1215        if "OK" not in dev[0].request("SET scan_cur_freq 1"):
1216            raise Exception("SET scan_cur_freq failed")
1217        check_scan(dev[0], "use_id=1")
1218    finally:
1219        dev[0].request("SET scan_cur_freq 0")
1220    dev[0].request("REMOVE_NETWORK all")
1221    dev[0].wait_disconnected()
1222
1223def test_scan_bss_limit(dev, apdev):
1224    """Scan and wpa_supplicant BSS entry limit"""
1225    try:
1226        _test_scan_bss_limit(dev, apdev)
1227    finally:
1228        dev[0].request("SET bss_max_count 200")
1229        pass
1230
1231def _test_scan_bss_limit(dev, apdev):
1232    dev[0].flush_scan_cache()
1233    # Trigger 'Increasing the MAX BSS count to 2 because all BSSes are in use.
1234    # We should normally not get here!' message by limiting the maximum BSS
1235    # count to one so that the second AP would not fit in the BSS list and the
1236    # first AP cannot be removed from the list since it is still in use.
1237    dev[0].request("SET bss_max_count 1")
1238    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1239    dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412")
1240    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "test-scan-2",
1241                                      "channel": "6"})
1242    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2437, force_scan=True)
1243
1244def run_scan(dev, bssid, exp_freq):
1245    for i in range(5):
1246        dev.request("SCAN freq=2412,2437,2462")
1247        ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"])
1248        if ev is None:
1249            raise Exception("Scan did not complete")
1250        bss = dev.get_bss(bssid)
1251        freq = int(bss['freq']) if bss else 0
1252        if freq == exp_freq:
1253            break
1254    if freq != exp_freq:
1255        raise Exception("BSS entry shows incorrect frequency: %d != %d" % (freq, exp_freq))
1256
1257def test_scan_chan_switch(dev, apdev):
1258    """Scanning and AP changing channels"""
1259
1260    # This test verifies that wpa_supplicant updates its local BSS table based
1261    # on the correct cfg80211 scan entry in cases where the cfg80211 BSS table
1262    # has multiple (one for each frequency) BSS entries for the same BSS.
1263
1264    csa_supported(dev[0])
1265    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan", "channel": "1"})
1266    csa_supported(hapd)
1267    bssid = hapd.own_addr()
1268
1269    logger.info("AP channel switch while not connected")
1270    run_scan(dev[0], bssid, 2412)
1271    dev[0].dump_monitor()
1272    switch_channel(hapd, 1, 2437)
1273    run_scan(dev[0], bssid, 2437)
1274    dev[0].dump_monitor()
1275    switch_channel(hapd, 1, 2462)
1276    run_scan(dev[0], bssid, 2462)
1277    dev[0].dump_monitor()
1278
1279    logger.info("AP channel switch while connected")
1280    dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412 2437 2462")
1281    run_scan(dev[0], bssid, 2462)
1282    dev[0].dump_monitor()
1283    switch_channel(hapd, 2, 2437)
1284    wait_channel_switch(dev[0], 2437)
1285    dev[0].dump_monitor()
1286    run_scan(dev[0], bssid, 2437)
1287    dev[0].dump_monitor()
1288    switch_channel(hapd, 2, 2412)
1289    wait_channel_switch(dev[0], 2412)
1290    dev[0].dump_monitor()
1291    run_scan(dev[0], bssid, 2412)
1292    dev[0].dump_monitor()
1293
1294def test_scan_new_only(dev, apdev):
1295    """Scan and only_new=1 multiple times"""
1296    dev[0].flush_scan_cache()
1297    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1298    dev[0].set("ignore_old_scan_res", "1")
1299    # Get the BSS added to cfg80211 BSS list
1300    bssid = hapd.own_addr()
1301    dev[0].scan_for_bss(bssid, freq=2412)
1302    bss = dev[0].get_bss(bssid)
1303    idx1 = bss['update_idx']
1304    dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
1305    dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
1306    bss = dev[0].get_bss(bssid)
1307    idx2 = bss['update_idx']
1308    if int(idx2) <= int(idx1):
1309        raise Exception("Scan result update_idx did not increase")
1310    # Disable AP to ensure there are no new scan results after this.
1311    hapd.disable()
1312
1313    # Try to scan multiple times to verify that old scan results do not get
1314    # accepted as new.
1315    for i in range(10):
1316        dev[0].scan(freq=2412)
1317        bss = dev[0].get_bss(bssid)
1318        if bss:
1319            idx = bss['update_idx']
1320            if int(idx) > int(idx2):
1321                raise Exception("Unexpected update_idx increase")
1322
1323def test_scan_flush(dev, apdev):
1324    """Ongoing scan and FLUSH"""
1325    dev[0].flush_scan_cache()
1326    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1327    dev[0].dump_monitor()
1328    dev[0].request("SCAN TYPE=ONLY freq=2412-2472 passive=1")
1329    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=10)
1330    if ev is None:
1331        raise Exception("Scan did not start")
1332    time.sleep(0.1)
1333    dev[0].request("FLUSH")
1334    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS",
1335                            "CTRL-EVENT-SCAN-FAILED",
1336                            "CTRL-EVENT-BSS-ADDED"], timeout=10)
1337    if ev is None:
1338        raise Exception("Scan did not complete")
1339    if "CTRL-EVENT-BSS-ADDED" in ev:
1340        raise Exception("Unexpected BSS entry addition after FLUSH")
1341
1342def test_scan_ies(dev, apdev):
1343    """Scan and both Beacon and Probe Response frame IEs"""
1344    dev[0].flush_scan_cache()
1345    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan",
1346                                     "beacon_int": "20"})
1347    bssid = hapd.own_addr()
1348    dev[0].dump_monitor()
1349
1350    for i in range(10):
1351        dev[0].request("SCAN TYPE=ONLY freq=2412 passive=1")
1352        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=15)
1353        if ev is None:
1354            raise Exception("Scan did not complete")
1355        if dev[0].get_bss(bssid):
1356            break
1357
1358    for i in range(10):
1359        dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
1360        bss = dev[0].get_bss(bssid)
1361        if 'beacon_ie' in bss:
1362            if bss['ie'] != bss['beacon_ie']:
1363                break
1364
1365    if not bss or 'beacon_ie' not in bss:
1366        raise Exception("beacon_ie not present")
1367    ie = parse_ie(bss['ie'])
1368    logger.info("ie: " + str(list(ie.keys())))
1369    beacon_ie = parse_ie(bss['beacon_ie'])
1370    logger.info("beacon_ie: " + str(list(ie.keys())))
1371    if bss['ie'] == bss['beacon_ie']:
1372        raise Exception("Both ie and beacon_ie show same data")
1373
1374def test_scan_parsing(dev, apdev):
1375    """Scan result parsing"""
1376    if "OK" not in dev[0].request("DRIVER_EVENT SCAN_RES START"):
1377        raise Exception("DRIVER_EVENT SCAN_RES START failed")
1378
1379    if "FAIL" not in dev[0].request("DRIVER_EVENT SCAN_RES foo "):
1380        raise Exception("Invalid DRIVER_EVENT SCAN_RES accepted")
1381
1382    tests = ["",
1383             "flags=ffffffff",
1384             "bssid=02:03:04:05:06:07",
1385             "freq=1234",
1386             "beacon_int=102",
1387             "caps=1234",
1388             "qual=10",
1389             "noise=10",
1390             "level=10",
1391             "tsf=1122334455667788",
1392             "age=123",
1393             "est_throughput=100",
1394             "snr=10",
1395             "parent_tsf=1122334455667788",
1396             "tsf_bssid=02:03:04:05:06:07",
1397             "ie=00",
1398             "beacon_ie=00",
1399             # Too long SSID
1400             "bssid=02:ff:00:00:00:01 ie=0033" + 33*'FF',
1401             # All parameters
1402             "flags=ffffffff bssid=02:ff:00:00:00:02 freq=1234 beacon_int=102 caps=1234 qual=10 noise=10 level=10 tsf=1122334455667788 age=123 est_throughput=100 snr=10 parent_tsf=1122334455667788 tsf_bssid=02:03:04:05:06:07 ie=000474657374 beacon_ie=000474657374",
1403             # Beacon IEs truncated
1404             "bssid=02:ff:00:00:00:03 ie=0000 beacon_ie=0003ffff",
1405             # Probe Response IEs truncated
1406             "bssid=02:ff:00:00:00:04 ie=00000101 beacon_ie=0000",
1407             # DMG (invalid caps)
1408             "bssid=02:ff:00:00:00:05 freq=58320 ie=0003646d67",
1409             # DMG (IBSS)
1410             "bssid=02:ff:00:00:00:06 freq=60480 caps=0001 ie=0003646d67",
1411             # DMG (PBSS)
1412             "bssid=02:ff:00:00:00:07 freq=62640 caps=0002 ie=0003646d67",
1413             # DMG (AP)
1414             "bssid=02:ff:00:00:00:08 freq=64800 caps=0003 ie=0003646d67",
1415             # Test BSS for updates
1416             "bssid=02:ff:00:00:00:09 freq=2412 caps=0011 level=1 ie=0003757064010182",
1417             # Minimal BSS data
1418             "bssid=02:ff:00:00:00:00 ie=0000"]
1419    for t in tests:
1420        if "OK" not in dev[0].request("DRIVER_EVENT SCAN_RES BSS " + t):
1421            raise Exception("DRIVER_EVENT SCAN_RES BSS failed")
1422
1423    if "OK" not in dev[0].request("DRIVER_EVENT SCAN_RES END"):
1424        raise Exception("DRIVER_EVENT SCAN_RES END failed")
1425
1426    res = dev[0].request("SCAN_RESULTS")
1427    logger.info("SCAN_RESULTS:\n" + res)
1428
1429    bss = []
1430    res = dev[0].request("BSS FIRST")
1431    if "FAIL" in res:
1432        raise Exception("BSS FIRST failed")
1433    while "\nbssid=" in res:
1434        logger.info("BSS output:\n" + res)
1435        bssid = None
1436        id = None
1437        for val in res.splitlines():
1438            if val.startswith("id="):
1439                id = val.split('=')[1]
1440            if val.startswith("bssid="):
1441                bssid = val.split('=')[1]
1442        if bssid is None or id is None:
1443            raise Exception("Missing id or bssid line")
1444        bss.append(bssid)
1445        res = dev[0].request("BSS NEXT-" + id)
1446
1447    logger.info("Discovered BSSs: " + str(bss))
1448    invalid_bss = ["02:03:04:05:06:07", "02:ff:00:00:00:01"]
1449    valid_bss = ["02:ff:00:00:00:00", "02:ff:00:00:00:02",
1450                 "02:ff:00:00:00:03", "02:ff:00:00:00:04",
1451                 "02:ff:00:00:00:05", "02:ff:00:00:00:06",
1452                 "02:ff:00:00:00:07", "02:ff:00:00:00:08",
1453                 "02:ff:00:00:00:09"]
1454    for bssid in invalid_bss:
1455        if bssid in bss:
1456            raise Exception("Invalid BSS included: " + bssid)
1457    for bssid in valid_bss:
1458        if bssid not in bss:
1459            raise Exception("Valid BSS missing: " + bssid)
1460
1461    logger.info("Update BSS parameters")
1462    if "OK" not in dev[0].request("DRIVER_EVENT SCAN_RES START"):
1463        raise Exception("DRIVER_EVENT SCAN_RES START failed")
1464    if "OK" not in dev[0].request("DRIVER_EVENT SCAN_RES BSS bssid=02:ff:00:00:00:09 freq=2412 caps=0002 level=2 ie=000375706401028204"):
1465        raise Exception("DRIVER_EVENT SCAN_RES BSS failed")
1466    if "OK" not in dev[0].request("DRIVER_EVENT SCAN_RES END"):
1467        raise Exception("DRIVER_EVENT SCAN_RES END failed")
1468    res = dev[0].request("BSS 02:ff:00:00:00:09")
1469    logger.info("Updated BSS:\n" + res)
1470
1471def get_probe_req_ies(hapd):
1472    for i in range(10):
1473        msg = hapd.mgmt_rx()
1474        if msg is None:
1475            break
1476        if msg['subtype'] != 4:
1477            continue
1478        return parse_ie(binascii.hexlify(msg['payload']).decode())
1479
1480    raise Exception("Probe Request not seen")
1481
1482def test_scan_specific_bssid(dev, apdev):
1483    """Scan for a specific BSSID"""
1484    dev[0].flush_scan_cache()
1485    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-scan",
1486                                     "beacon_int": "1000"})
1487    bssid = hapd.own_addr()
1488
1489    time.sleep(0.1)
1490    dev[0].request("SCAN TYPE=ONLY freq=2412 bssid=02:ff:ff:ff:ff:ff")
1491    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
1492    if ev is None:
1493        raise Exception("Scan did not complete")
1494    bss1 = dev[0].get_bss(bssid)
1495
1496    for i in range(10):
1497        dev[0].request("SCAN TYPE=ONLY freq=2412 bssid=" + bssid)
1498        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
1499        if ev is None:
1500            raise Exception("Scan did not complete")
1501        bss2 = dev[0].get_bss(bssid)
1502        if bss2:
1503            break
1504
1505    if not bss2:
1506        raise Exception("Did not find BSS")
1507    if bss1 and 'beacon_ie' in bss1 and 'ie' in bss1 and bss1['beacon_ie'] != bss1['ie']:
1508        raise Exception("First scan for unknown BSSID returned unexpected response")
1509    if bss2 and 'beacon_ie' in bss2 and 'ie' in bss2 and bss2['beacon_ie'] == bss2['ie']:
1510        raise Exception("Second scan did find Probe Response frame")
1511
1512    hapd.dump_monitor()
1513    hapd.set("ext_mgmt_frame_handling", "1")
1514
1515    # With specific SSID in the Probe Request frame
1516    dev[0].request("SCAN TYPE=ONLY freq=2412 bssid=" + bssid)
1517    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
1518    if ev is None:
1519        raise Exception("Scan did not complete")
1520    ie = get_probe_req_ies(hapd)
1521    if ie[0] != b"test-scan":
1522        raise Exception("Specific SSID not seen in Probe Request frame")
1523
1524    hapd.dump_monitor()
1525
1526    # Without specific SSID in the Probe Request frame
1527    dev[0].request("SCAN TYPE=ONLY freq=2412 wildcard_ssid=1 bssid=" + bssid)
1528    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
1529    if ev is None:
1530        raise Exception("Scan did not complete")
1531    ie = get_probe_req_ies(hapd)
1532    if len(ie[0]) != 0:
1533        raise Exception("Wildcard SSID not seen in Probe Request frame")
1534
1535def test_scan_probe_req_events(dev, apdev):
1536    """Probe Request frame RX events from hostapd"""
1537    run_scan_probe_req_events(dev, apdev)
1538
1539def test_scan_probe_req_events_with_payload(dev, apdev):
1540    """Probe Request frame RX events with payload from hostapd"""
1541    run_scan_probe_req_events(dev, apdev, with_payload=True)
1542
1543def run_scan_probe_req_events(dev, apdev, with_payload=False):
1544    params = {"ssid": "open"}
1545    if with_payload:
1546        params["notify_mgmt_frames"] = "1"
1547    hapd = hostapd.add_ap(apdev[0], params)
1548    hapd2 = hostapd.Hostapd(apdev[0]['ifname'])
1549    if "OK" not in hapd2.mon.request("ATTACH probe_rx_events=1"):
1550        raise Exception("Failed to register for events")
1551
1552    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
1553
1554    ev = hapd2.wait_event(["RX-PROBE-REQUEST"], timeout=5)
1555    if ev is None:
1556        raise Exception("RX-PROBE-REQUEST not reported")
1557    if "sa=" + dev[0].own_addr() not in ev:
1558        raise Exception("Unexpected event parameters: " + ev)
1559    if with_payload and " buf=40" not in ev:
1560        raise Exception("Missing payload in event parameters: " + ev)
1561
1562    ev = hapd.wait_event(["RX-PROBE-REQUEST"], timeout=0.1)
1563    if ev is not None:
1564        raise Exception("Unexpected RX-PROBE-REQUEST")
1565
1566    if "OK" not in hapd2.mon.request("ATTACH probe_rx_events=0"):
1567        raise Exception("Failed to update event registration")
1568
1569    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
1570    ev = hapd2.wait_event(["RX-PROBE-REQUEST"], timeout=0.5)
1571    if ev is not None:
1572        raise Exception("Unexpected RX-PROBE-REQUEST")
1573
1574    tests = ["probe_rx_events", "probe_rx_events=-1", "probe_rx_events=2"]
1575    for val in tests:
1576        if "FAIL" not in hapd2.mon.request("ATTACH " + val):
1577            raise Exception("Invalid ATTACH command accepted")
1578
1579def elem_capab(capab):
1580    # Nontransmitted BSSID Capability element (83 = 0x53)
1581    return struct.pack('<BBH', 83, 2, capab)
1582
1583def elem_ssid(ssid):
1584    # SSID element
1585    return struct.pack('BB', 0, len(ssid)) + ssid.encode()
1586
1587def elem_bssid_index(index):
1588    # Multiple BSSID-index element (85 = 0x55)
1589    return struct.pack('BBB', 85, 1, index)
1590
1591def elem_multibssid(profiles, max_bssid_indic):
1592    # TODO: add support for fragmenting over multiple Multiple BSSID elements
1593    if 1 + len(profiles) > 255:
1594        raise Exception("Too long Multiple BSSID element")
1595    elem = struct.pack('BBB', 71, 1 + len(profiles), max_bssid_indic) + profiles
1596    return binascii.hexlify(elem).decode()
1597
1598def run_scans(dev, check):
1599    for i in range(2):
1600        dev.request("SCAN TYPE=ONLY freq=2412")
1601        ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
1602        if ev is None:
1603            raise Exception("Scan did not complete")
1604
1605    # TODO: Check IEs
1606    for (bssid, ssid, capab) in check:
1607        bss = dev.get_bss(bssid)
1608        if bss is None:
1609            raise Exception("AP " + bssid + " missing from scan results")
1610        logger.info("AP " + bssid + ": " + str(bss))
1611        if bss['ssid'] != ssid:
1612            raise Exception("Unexpected AP " + bssid + " SSID")
1613        if int(bss['capabilities'], 16) != capab:
1614            raise Exception("Unexpected AP " + bssid + " capabilities")
1615
1616def check_multibss_sta_capa(dev):
1617    res = dev.get_capability("multibss")
1618    if res is None or 'MULTIBSS-STA' not in res:
1619        raise HwsimSkip("Multi-BSS STA functionality not supported")
1620
1621def test_scan_multi_bssid(dev, apdev):
1622    """Scan and Multiple BSSID element"""
1623    check_multibss_sta_capa(dev[0])
1624    dev[0].flush_scan_cache()
1625
1626    params = {"ssid": "test-scan"}
1627    # Max BSSID Indicator 0 (max 1 BSSID) and no subelements
1628    params['vendor_elements'] = elem_multibssid(b'', 0)
1629    hostapd.add_ap(apdev[0], params)
1630
1631    params = {"ssid": "test-scan"}
1632    elems = elem_capab(0x0401) + elem_ssid("1") + elem_bssid_index(1)
1633    profile1 = struct.pack('BB', 0, len(elems)) + elems
1634    params['vendor_elements'] = elem_multibssid(profile1, 1)
1635    hostapd.add_ap(apdev[1], params)
1636
1637    bssid0 = apdev[0]['bssid']
1638    bssid1 = apdev[1]['bssid']
1639    check = [(bssid0, 'test-scan', 0x401),
1640             (bssid1, 'test-scan', 0x401),
1641             (bssid1[0:16] + '1', '1', 0x401)]
1642    run_scans(dev[0], check)
1643
1644def test_scan_multi_bssid_2(dev, apdev):
1645    """Scan and Multiple BSSID element (2)"""
1646    check_multibss_sta_capa(dev[0])
1647    dev[0].flush_scan_cache()
1648
1649    params = {"ssid": "transmitted"}
1650
1651    # Duplicated entry for the transmitted BSS (not a normal use case)
1652    elems = elem_capab(1) + elem_ssid("transmitted") + elem_bssid_index(0)
1653    profile1 = struct.pack('BB', 0, len(elems)) + elems
1654
1655    elems = elem_capab(1) + elem_ssid("nontransmitted") + elem_bssid_index(1)
1656    profile2 = struct.pack('BB', 0, len(elems)) + elems
1657
1658    elems = elem_capab(1) + elem_ssid("nontransmitted_2") + elem_bssid_index(2)
1659    profile3 = struct.pack('BB', 0, len(elems)) + elems
1660
1661    profiles = profile1 + profile2 + profile3
1662    params['vendor_elements'] = elem_multibssid(profiles, 4)
1663    hostapd.add_ap(apdev[0], params)
1664
1665    bssid = apdev[0]['bssid']
1666    check = [(bssid, 'transmitted', 0x401),
1667             (bssid[0:16] + '1', 'nontransmitted', 0x1),
1668             (bssid[0:16] + '2', 'nontransmitted_2', 0x1)]
1669    run_scans(dev[0], check)
1670
1671def test_scan_multi_bssid_3(dev, apdev):
1672    """Scan and Multiple BSSID element (3)"""
1673    check_multibss_sta_capa(dev[0])
1674    dev[0].flush_scan_cache()
1675
1676    params = {"ssid": "transmitted"}
1677
1678    # Duplicated nontransmitted BSS (not a normal use case)
1679    elems = elem_capab(1) + elem_ssid("nontransmitted") + elem_bssid_index(1)
1680    profile1 = struct.pack('BB', 0, len(elems)) + elems
1681
1682    elems = elem_capab(1) + elem_ssid("nontransmitted") + elem_bssid_index(1)
1683    profile2 = struct.pack('BB', 0, len(elems)) + elems
1684
1685    profiles = profile1 + profile2
1686    params['vendor_elements'] = elem_multibssid(profiles, 2)
1687    hostapd.add_ap(apdev[0], params)
1688
1689    bssid = apdev[0]['bssid']
1690    check = [(bssid, 'transmitted', 0x401),
1691             (bssid[0:16] + '1', 'nontransmitted', 0x1)]
1692    run_scans(dev[0], check)
1693
1694def test_scan_multi_bssid_4(dev, apdev):
1695    """Scan and Multiple BSSID element (3)"""
1696    check_multibss_sta_capa(dev[0])
1697    dev[0].flush_scan_cache()
1698
1699    # Transmitted BSSID is not the first one in the block
1700    bssid = apdev[0]['bssid']
1701    hapd = None
1702    try:
1703        params = {"ssid": "transmitted",
1704                  "bssid": bssid[0:16] + '1'}
1705
1706        elems = elem_capab(1) + elem_ssid("1") + elem_bssid_index(1)
1707        profile1 = struct.pack('BB', 0, len(elems)) + elems
1708
1709        elems = elem_capab(1) + elem_ssid("2") + elem_bssid_index(2)
1710        profile2 = struct.pack('BB', 0, len(elems)) + elems
1711
1712        elems = elem_capab(1) + elem_ssid("3") + elem_bssid_index(3)
1713        profile3 = struct.pack('BB', 0, len(elems)) + elems
1714
1715        profiles = profile1 + profile2 + profile3
1716        params['vendor_elements'] = elem_multibssid(profiles, 2)
1717        hapd = hostapd.add_ap(apdev[0], params)
1718
1719        check = [(bssid[0:16] + '1', 'transmitted', 0x401),
1720                 (bssid[0:16] + '2', '1', 0x1),
1721                 (bssid[0:16] + '3', '2', 0x1),
1722                 (bssid[0:16] + '0', '3', 0x1)]
1723        run_scans(dev[0], check)
1724    finally:
1725        if hapd:
1726            hapd.disable()
1727            hapd.set('bssid', bssid)
1728            hapd.enable()
1729
1730def test_scan_multi_bssid_check_ie(dev, apdev):
1731    """Scan and check if nontransmitting BSS inherits IE from transmitting BSS"""
1732    check_multibss_sta_capa(dev[0])
1733    dev[0].flush_scan_cache()
1734
1735    params = {"ssid": "transmitted"}
1736
1737    # Duplicated entry for the transmitted BSS (not a normal use case)
1738    elems = elem_capab(1) + elem_ssid("transmitted") + elem_bssid_index(0)
1739    profile1 = struct.pack('BB', 0, len(elems)) + elems
1740
1741    elems = elem_capab(1) + elem_ssid("nontransmitted") + elem_bssid_index(1)
1742    profile2 = struct.pack('BB', 0, len(elems)) + elems
1743
1744    profiles = profile1 + profile2
1745    params['vendor_elements'] = elem_multibssid(profiles, 2)
1746    hostapd.add_ap(apdev[0], params)
1747
1748    bssid = apdev[0]['bssid']
1749
1750    for i in range(10):
1751        dev[0].request("SCAN TYPE=ONLY freq=2412 passive=1")
1752        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=15)
1753        if ev is None:
1754            raise Exception("Scan did not complete")
1755        if dev[0].get_bss(bssid):
1756            break
1757
1758    for i in range(10):
1759        dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
1760        bss = dev[0].get_bss(bssid)
1761        if 'beacon_ie' in bss:
1762            break
1763
1764    trans_bss = dev[0].get_bss(bssid)
1765    if trans_bss is None:
1766        raise Exception("AP " + bssid + " missing from scan results")
1767
1768    if not trans_bss or 'beacon_ie' not in trans_bss:
1769        raise Exception("beacon_ie not present in trans_bss")
1770
1771    beacon_ie = parse_ie(trans_bss['beacon_ie'])
1772    logger.info("trans_bss beacon_ie: " + str(list(beacon_ie.keys())))
1773
1774    bssid = bssid[0:16] + '1'
1775    nontrans_bss1 = dev[0].get_bss(bssid)
1776    if nontrans_bss1 is None:
1777        raise Exception("AP " + bssid + " missing from scan results")
1778
1779    if not trans_bss or 'beacon_ie' not in nontrans_bss1:
1780        raise Exception("beacon_ie not present in nontrans_bss1")
1781
1782    nontx_beacon_ie = parse_ie(nontrans_bss1['beacon_ie'])
1783    logger.info("nontrans_bss1 beacon_ie: " + str(list(nontx_beacon_ie.keys())))
1784
1785    if 71 in list(beacon_ie.keys()):
1786        ie_list = list(beacon_ie.keys())
1787        ie_list.remove(71)
1788        nontx_ie_list = list(nontx_beacon_ie.keys())
1789        try:
1790            nontx_ie_list.remove(85)
1791        except ValueError:
1792            pass
1793        if sorted(ie_list) != sorted(nontx_ie_list):
1794            raise Exception("check IE failed")
1795
1796def elem_fms1():
1797    # this FMS IE has 1 FMS counter
1798    fms_counters = struct.pack('B', 0x39)
1799    fms_ids = struct.pack('B', 0x01)
1800    return struct.pack('BBB', 86, 3, 1) + fms_counters + fms_ids
1801
1802def elem_fms2():
1803    # this FMS IE has 2 FMS counters
1804    fms_counters = struct.pack('BB', 0x29, 0x32)
1805    fms_ids = struct.pack('BB', 0x01, 0x02)
1806    return struct.pack('BBB', 86, 5, 2) + fms_counters + fms_ids
1807
1808def test_scan_multi_bssid_fms(dev, apdev):
1809    """Non-transmitting BSS has different FMS IE from transmitting BSS"""
1810    check_multibss_sta_capa(dev[0])
1811    dev[0].flush_scan_cache()
1812
1813    params = {"ssid": "transmitted"}
1814
1815    # construct transmitting BSS Beacon with FMS IE
1816    elems = elem_capab(1) + elem_ssid("transmitted") + elem_bssid_index(0) + elem_fms1()
1817    profile1 = struct.pack('BB', 0, len(elems)) + elems
1818
1819    elems = elem_capab(1) + elem_ssid("nontransmitted") + elem_bssid_index(1) + elem_fms2()
1820    profile2 = struct.pack('BB', 0, len(elems)) + elems
1821
1822    profiles = profile1 + profile2
1823    params['vendor_elements'] = elem_multibssid(profiles, 2) + binascii.hexlify(elem_fms1()).decode()
1824    hostapd.add_ap(apdev[0], params)
1825
1826    bssid = apdev[0]['bssid']
1827
1828    for i in range(10):
1829        dev[0].request("SCAN TYPE=ONLY freq=2412 passive=1")
1830        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=15)
1831        if ev is None:
1832            raise Exception("Scan did not complete")
1833        if dev[0].get_bss(bssid):
1834            break
1835
1836    for i in range(10):
1837        dev[0].scan_for_bss(bssid, freq=2412, force_scan=True)
1838        bss = dev[0].get_bss(bssid)
1839        if 'beacon_ie' in bss:
1840            break
1841
1842    trans_bss = dev[0].get_bss(bssid)
1843    if trans_bss is None:
1844        raise Exception("AP " + bssid + " missing from scan results")
1845
1846    if not trans_bss or 'beacon_ie' not in trans_bss:
1847        raise Exception("beacon_ie not present in trans_bss")
1848
1849    beacon_ie = parse_ie(trans_bss['beacon_ie'])
1850    trans_bss_fms = beacon_ie[86]
1851    logger.info("trans_bss fms ie: " + binascii.hexlify(trans_bss_fms).decode())
1852
1853    bssid = bssid[0:16] + '1'
1854    nontrans_bss1 = dev[0].get_bss(bssid)
1855    if nontrans_bss1 is None:
1856        raise Exception("AP " + bssid + " missing from scan results")
1857
1858    if not nontrans_bss1 or 'beacon_ie' not in nontrans_bss1:
1859        raise Exception("beacon_ie not present in nontrans_bss1")
1860
1861    nontrans_beacon_ie = parse_ie(nontrans_bss1['beacon_ie'])
1862    nontrans_bss_fms = nontrans_beacon_ie[86]
1863    logger.info("nontrans_bss fms ie: " + binascii.hexlify(nontrans_bss_fms).decode())
1864
1865    if binascii.hexlify(trans_bss_fms) == binascii.hexlify(nontrans_bss_fms):
1866        raise Exception("Nontrans BSS has the same FMS IE as trans BSS")
1867
1868def test_scan_multiple_mbssid_ie(dev, apdev):
1869    """Transmitting BSS has 2 MBSSID IE"""
1870    check_multibss_sta_capa(dev[0])
1871    dev[0].flush_scan_cache()
1872
1873    bssid = apdev[0]['bssid']
1874    logger.info("bssid: " + bssid)
1875    hapd = None
1876
1877    # construct 2 MBSSID IEs, each MBSSID IE contains 1 profile
1878    params = {"ssid": "transmitted",
1879              "bssid": bssid}
1880
1881    elems = elem_capab(1) + elem_ssid("1") + elem_bssid_index(1)
1882    profile1 = struct.pack('BB', 0, len(elems)) + elems
1883
1884    elems = elem_capab(2) + elem_ssid("2") + elem_bssid_index(2)
1885    profile2 = struct.pack('BB', 0, len(elems)) + elems
1886
1887    params['vendor_elements'] = elem_multibssid(profile1, 2) + elem_multibssid(profile2, 2)
1888    hapd = hostapd.add_ap(apdev[0], params)
1889
1890    check = [(bssid, 'transmitted', 0x401),
1891             (bssid[0:16] + '1', '1', 0x1),
1892             (bssid[0:16] + '2', '2', 0x2)]
1893    run_scans(dev[0], check)
1894
1895def test_scan_mbssid_hidden_ssid(dev, apdev):
1896    """Non-transmitting BSS has hidden SSID"""
1897    check_multibss_sta_capa(dev[0])
1898    dev[0].flush_scan_cache()
1899
1900    bssid = apdev[0]['bssid']
1901    logger.info("bssid: " + bssid)
1902    hapd = None
1903
1904    # construct 2 MBSSID IEs, each MBSSID IE contains 1 profile
1905    params = {"ssid": "transmitted",
1906              "bssid": bssid}
1907
1908    elems = elem_capab(1) + elem_ssid("") + elem_bssid_index(1)
1909    profile1 = struct.pack('BB', 0, len(elems)) + elems
1910
1911    elems = elem_capab(2) + elem_ssid("2") + elem_bssid_index(2)
1912    profile2 = struct.pack('BB', 0, len(elems)) + elems
1913
1914    profiles = profile1 + profile2
1915    params['vendor_elements'] = elem_multibssid(profiles, 2)
1916    hapd = hostapd.add_ap(apdev[0], params)
1917
1918    check = [(bssid, 'transmitted', 0x401),
1919             (bssid[0:16] + '1', '', 0x1),
1920             (bssid[0:16] + '2', '2', 0x2)]
1921    run_scans(dev[0], check)
1922
1923def test_connect_mbssid_open_1(dev, apdev):
1924    """Connect to transmitting and nontransmitting BSS in open mode"""
1925    check_multibss_sta_capa(dev[0])
1926    dev[0].flush_scan_cache()
1927
1928    bssid = apdev[0]['bssid']
1929    params = {"ssid": "transmitted"}
1930
1931    elems = elem_capab(1) + elem_ssid("nontransmitted") + elem_bssid_index(1)
1932    profile1 = struct.pack('BB', 0, len(elems)) + elems
1933
1934    elems = elem_capab(1) + elem_ssid("nontransmitted_2") + elem_bssid_index(2)
1935    profile2 = struct.pack('BB', 0, len(elems)) + elems
1936
1937    profiles = profile1 + profile2
1938    params['vendor_elements'] = elem_multibssid(profiles, 4)
1939    hostapd.add_ap(apdev[0], params)
1940
1941    dev[0].connect("transmitted", key_mgmt="NONE", scan_freq="2412")
1942    dev[0].request("REMOVE_NETWORK all")
1943    dev[0].wait_disconnected()
1944    dev[0].dump_monitor()
1945
1946    dev[0].connect("nontransmitted", key_mgmt="NONE", scan_freq="2412",
1947                   wait_connect=False)
1948    ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=10)
1949    if ev is None:
1950        raise Exception("Connection attempt to nontransmitted BSS not started")
1951    if "02:00:00:00:03:01 (SSID='nontransmitted'" not in ev:
1952        raise Exception("Unexpected authentication target")
1953    # hostapd does not yet support Multiple-BSSID, so only verify that STA is
1954    # able to start connection attempt.
1955    dev[0].request("REMOVE_NETWORK all")
1956    dev[0].dump_monitor()
1957
1958    dev[0].connect("nontransmitted_2", key_mgmt="NONE", scan_freq="2412",
1959                   wait_connect=False)
1960    ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=10)
1961    if ev is None:
1962        raise Exception("Connection attempt to nontransmitted BSS not started")
1963    if "02:00:00:00:03:02 (SSID='nontransmitted_2'" not in ev:
1964        raise Exception("Unexpected authentication target")
1965    # hostapd does not yet support Multiple-BSSID, so only verify that STA is
1966    # able to start connection attempt.
1967    dev[0].request("REMOVE_NETWORK all")
1968    dev[0].dump_monitor()
1969
1970def test_scan_only_one(dev, apdev):
1971    """Test that scanning with a single active AP only returns that one"""
1972    dev[0].flush_scan_cache()
1973    hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
1974    bssid = apdev[0]['bssid']
1975
1976    check_scan(dev[0], "use_id=1", test_busy=True)
1977    dev[0].scan_for_bss(bssid, freq="2412")
1978
1979    status, stdout = hostapd.cmd_execute(dev[0], ['iw', dev[0].ifname, 'scan', 'dump'])
1980    if status != 0:
1981        raise Exception("iw scan dump failed with code %d" % status)
1982    lines = stdout.split('\n')
1983    entries = len(list(filter(lambda x: x.startswith('BSS '), lines)))
1984    if entries != 1:
1985        raise Exception("expected to find 1 BSS entry, got %d" % entries)
1986
1987def test_scan_ssid_list(dev, apdev):
1988    """Scan using SSID List element"""
1989    dev[0].flush_scan_cache()
1990    ssid = "test-ssid-list"
1991    hapd = hostapd.add_ap(apdev[0], {"ssid": ssid,
1992                                     "ignore_broadcast_ssid": "1"})
1993    bssid = apdev[0]['bssid']
1994    found = False
1995    try:
1996        payload = struct.pack('BB', 0, len(ssid)) + ssid.encode()
1997        ssid_list = struct.pack('BB', 84, len(payload)) + payload
1998        cmd = "VENDOR_ELEM_ADD 14 " + binascii.hexlify(ssid_list).decode()
1999        if "OK" not in dev[0].request(cmd):
2000            raise Exception("VENDOR_ELEM_ADD failed")
2001        for i in range(10):
2002            check_scan(dev[0], "freq=2412 use_id=1")
2003            if ssid in dev[0].request("SCAN_RESULTS"):
2004                found = True
2005                break
2006    finally:
2007        dev[0].request("VENDOR_ELEM_REMOVE 14 *")
2008        hapd.disable()
2009        dev[0].flush_scan_cache(freq=2432)
2010        dev[0].flush_scan_cache()
2011
2012    if not found:
2013        raise Exception("AP not found in scan results")
2014
2015def test_scan_short_ssid_list(dev, apdev):
2016    """Scan using Short SSID List element"""
2017    dev[0].flush_scan_cache()
2018    ssid = "test-short-ssid-list"
2019    hapd = hostapd.add_ap(apdev[0], {"ssid": ssid,
2020                                     "ignore_broadcast_ssid": "1"})
2021    bssid = apdev[0]['bssid']
2022    found = False
2023    try:
2024        payload = struct.pack('<L', binascii.crc32(ssid.encode()))
2025        ssid_list = struct.pack('BBB', 255, 1 + len(payload), 58) + payload
2026        cmd = "VENDOR_ELEM_ADD 14 " + binascii.hexlify(ssid_list).decode()
2027        if "OK" not in dev[0].request(cmd):
2028            raise Exception("VENDOR_ELEM_ADD failed")
2029        for i in range(10):
2030            check_scan(dev[0], "freq=2412 use_id=1")
2031            if ssid in dev[0].request("SCAN_RESULTS"):
2032                found = True
2033                break
2034    finally:
2035        dev[0].request("VENDOR_ELEM_REMOVE 14 *")
2036        hapd.disable()
2037        dev[0].flush_scan_cache(freq=2432)
2038        dev[0].flush_scan_cache()
2039
2040    if not found:
2041        raise Exception("AP not found in scan results")
2042