1# Radio measurement
2# Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
3# Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
4# Copyright (c) 2017, Jouni Malinen <j@w1.fi>
5#
6# This software may be distributed under the terms of the BSD license.
7# See README for more details.
8
9import binascii
10import re
11import logging
12logger = logging.getLogger()
13import struct
14import subprocess
15import time
16
17import hostapd
18from wpasupplicant import WpaSupplicant
19from utils import *
20from remotehost import remote_compatible
21
22def check_rrm_support(dev):
23    rrm = int(dev.get_driver_status_field("capa.rrm_flags"), 16)
24    if rrm & 0x5 != 0x5 and rrm & 0x10 != 0x10:
25        raise HwsimSkip("Required RRM capabilities are not supported")
26
27def check_tx_power_support(dev):
28    rrm = int(dev.get_driver_status_field("capa.rrm_flags"), 16)
29    if rrm & 0x8 != 0x8:
30        raise HwsimSkip("Required RRM capabilities are not supported")
31
32nr = "00112233445500000000510107"
33lci = "01000800101298c0b512926666f6c2f1001c00004104050000c00012"
34civic = "01000b0011223344556677889900998877665544332211aabbccddeeff"
35
36def check_nr_results(dev, bssids=None, lci=False, civic=False):
37    if bssids is None:
38        ev = dev.wait_event(["RRM-NEIGHBOR-REP-REQUEST-FAILED"], timeout=10)
39        if ev is None:
40            raise Exception("RRM neighbor report failure not received")
41        return
42
43    received = []
44    for bssid in bssids:
45        ev = dev.wait_event(["RRM-NEIGHBOR-REP-RECEIVED"], timeout=10)
46        if ev is None:
47            raise Exception("RRM report result not indicated")
48        received.append(ev)
49
50    for bssid in bssids:
51        found = False
52        for r in received:
53            if "RRM-NEIGHBOR-REP-RECEIVED bssid=" + bssid in r:
54                if lci and "lci=" not in r:
55                    raise Exception("LCI data not reported for %s" % bssid)
56                if civic and "civic=" not in r:
57                    raise Exception("civic data not reported for %s" % bssid)
58                received.remove(r)
59                found = True
60                break
61        if not found:
62            raise Exception("RRM report result for %s not indicated" % bssid)
63
64def test_rrm_neighbor_db(dev, apdev):
65    """hostapd ctrl_iface SET_NEIGHBOR"""
66    params = {"ssid": "test", "rrm_neighbor_report": "1"}
67    hapd = hostapd.add_ap(apdev[0], params)
68    params = {"ssid": "test2", "rrm_neighbor_report": "1"}
69    hapd2 = hostapd.add_ap(apdev[1], params)
70
71    res = hapd.request("SHOW_NEIGHBOR")
72    if len(res.splitlines()) != 1:
73        raise Exception("Unexpected SHOW_NEIGHBOR output(1): " + res)
74    if apdev[0]['bssid'] not in res:
75        raise Exception("Own BSS not visible in SHOW_NEIGHBOR output")
76
77    if "OK" not in hapd2.request("SET_NEIGHBOR " + res.strip()):
78        raise Exception("Failed to copy neighbor entry to another hostapd")
79    res2 = hapd2.request("SHOW_NEIGHBOR")
80    if len(res2.splitlines()) != 2:
81        raise Exception("Unexpected SHOW_NEIGHBOR output: " + res2)
82    if res not in res2:
83        raise Exception("Copied entry not visible")
84
85    # Bad BSSID
86    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:gg ssid=\"test1\" nr=" + nr):
87        raise Exception("Set neighbor succeeded unexpectedly")
88
89    # Bad SSID
90    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=test1 nr=" + nr):
91        raise Exception("Set neighbor succeeded unexpectedly")
92
93    # Bad SSID end
94    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1 nr=" + nr):
95        raise Exception("Set neighbor succeeded unexpectedly")
96
97    # No SSID
98    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 nr=" + nr):
99        raise Exception("Set neighbor succeeded unexpectedly")
100
101    # No NR
102    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
103        raise Exception("Set neighbor succeeded unexpectedly")
104
105    # Odd length of NR
106    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr[:-1]):
107        raise Exception("Set neighbor succeeded unexpectedly")
108
109    # Invalid lci
110    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=1"):
111        raise Exception("Set neighbor succeeded unexpectedly")
112
113    # Invalid civic
114    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " civic=1"):
115        raise Exception("Set neighbor succeeded unexpectedly")
116
117    # No entry yet in database
118    if "FAIL" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
119        raise Exception("Remove neighbor succeeded unexpectedly")
120
121    # Add a neighbor entry
122    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic):
123        raise Exception("Set neighbor failed")
124
125    res = hapd.request("SHOW_NEIGHBOR")
126    if len(res.splitlines()) != 2:
127        raise Exception("Unexpected SHOW_NEIGHBOR output(2): " + res)
128    if apdev[0]['bssid'] not in res:
129        raise Exception("Own BSS not visible in SHOW_NEIGHBOR output")
130    if "00:11:22:33:44:55" not in res:
131        raise Exception("Added BSS not visible in SHOW_NEIGHBOR output")
132
133    # Another BSSID with the same SSID
134    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:56 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic):
135        raise Exception("Set neighbor failed")
136
137    res = hapd.request("SHOW_NEIGHBOR")
138    if len(res.splitlines()) != 3:
139        raise Exception("Unexpected SHOW_NEIGHBOR output(3): " + res)
140    if apdev[0]['bssid'] not in res:
141        raise Exception("Own BSS not visible in SHOW_NEIGHBOR output")
142    if "00:11:22:33:44:55" not in res:
143        raise Exception("Added BSS not visible in SHOW_NEIGHBOR output")
144    if "00:11:22:33:44:56" not in res:
145        raise Exception("Second added BSS not visible in SHOW_NEIGHBOR output")
146
147    # Fewer parameters
148    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr):
149        raise Exception("Set neighbor failed")
150
151    # SSID in hex format
152    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=7465737431 nr=" + nr):
153        raise Exception("Set neighbor failed")
154
155    # With more parameters
156    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " civic=" + civic):
157        raise Exception("Set neighbor failed")
158
159    # With all parameters
160    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic):
161        raise Exception("Set neighbor failed")
162
163    # Another SSID on the same BSSID
164    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test2\" nr=" + nr + " lci=" + lci):
165        raise Exception("Set neighbor failed")
166
167    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
168        raise Exception("Remove neighbor failed")
169
170    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:56 ssid=\"test1\""):
171        raise Exception("Remove neighbor failed")
172
173    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test2\""):
174        raise Exception("Remove neighbor failed")
175
176    # Double remove
177    if "FAIL" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
178        raise Exception("Remove neighbor succeeded unexpectedly")
179
180    # Stationary AP
181    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test3\" nr=" + nr + " lci=" + lci + " civic=" + civic + " stat"):
182        raise Exception("Set neighbor failed")
183
184    res = hapd.request("SHOW_NEIGHBOR")
185    if len(res.splitlines()) != 2:
186        raise Exception("Unexpected SHOW_NEIGHBOR output(4): " + res)
187    if "00:11:22:33:44:55" not in res or " stat" not in res:
188        raise Exception("Unexpected SHOW_NEIGHBOR output(4b): " + res)
189
190    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test3\""):
191        raise Exception("Remove neighbor failed")
192
193    # Add an entry for following REMOVE_NEIGHBOR tests
194    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=7465737431 nr=" + nr):
195        raise Exception("Set neighbor failed")
196
197    # Invalid remove - bad BSSID
198    if "FAIL" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:5 ssid=\"test1\""):
199        raise Exception("Remove neighbor succeeded unexpectedly")
200
201    # Invalid remove - bad SSID
202    if "FAIL" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1"):
203        raise Exception("Remove neighbor succeeded unexpectedly")
204
205    # Remove without specifying SSID
206    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55"):
207        raise Exception("Remove neighbor without SSID failed")
208
209    res = hapd.request("SHOW_NEIGHBOR")
210    if len(res.splitlines()) != 1:
211        raise Exception("Unexpected SHOW_NEIGHBOR output(5): " + res)
212    if apdev[0]['bssid'] not in res:
213        raise Exception("Own BSS not visible in SHOW_NEIGHBOR output")
214
215def test_rrm_neighbor_db_failures(dev, apdev):
216    """hostapd ctrl_iface SET_NEIGHBOR failures"""
217    params = {"ssid": "test", "rrm_neighbor_report": "1"}
218    hapd = hostapd.add_ap(apdev[0], params)
219    cmd = "SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic
220    tests = [(1, "hostapd_neighbor_add"),
221             (1, "wpabuf_dup;hostapd_neighbor_set"),
222             (2, "wpabuf_dup;hostapd_neighbor_set"),
223             (3, "wpabuf_dup;hostapd_neighbor_set")]
224    for count, func in tests:
225        with alloc_fail(hapd, count, func):
226            if "FAIL" not in hapd.request(cmd):
227                raise Exception("Set neighbor succeeded")
228
229def test_rrm_neighbor_db_disabled(dev, apdev):
230    """hostapd ctrl_iface SHOW_NEIGHBOR while neighbor report disabled"""
231    params = {"ssid": "test"}
232    hapd = hostapd.add_ap(apdev[0], params)
233    if "FAIL" not in hapd.request("SHOW_NEIGHBOR"):
234        raise Exception("SHOW_NEIGHBOR accepted")
235
236def test_rrm_neighbor_rep_req(dev, apdev):
237    """wpa_supplicant ctrl_iface NEIGHBOR_REP_REQUEST"""
238    check_rrm_support(dev[0])
239
240    nr1 = "00112233445500000000510107"
241    nr2 = "00112233445600000000510107"
242    nr3 = "dd112233445500000000510107"
243
244    params = {"ssid": "test", "rnr": "1"}
245    hostapd.add_ap(apdev[0], params)
246    params = {"ssid": "test2", "rrm_neighbor_report": "1", "rnr": "1"}
247    hapd = hostapd.add_ap(apdev[1], params)
248
249    bssid1 = apdev[1]['bssid']
250
251    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
252    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
253        raise Exception("Request succeeded unexpectedly (AP without RRM)")
254    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"abcdef\""):
255        raise Exception("Request succeeded unexpectedly (AP without RRM 2)")
256    dev[0].request("DISCONNECT")
257
258    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
259
260    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
261        raise Exception("Request failed")
262    check_nr_results(dev[0], [bssid1])
263
264    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST lci"):
265        raise Exception("Request failed")
266    check_nr_results(dev[0], [bssid1])
267
268    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST lci civic"):
269        raise Exception("Request failed")
270    check_nr_results(dev[0], [bssid1])
271
272    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\""):
273        raise Exception("Request failed")
274    check_nr_results(dev[0])
275
276    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" lci civic"):
277        raise Exception("Request failed")
278    check_nr_results(dev[0])
279
280    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test3\" nr=" + nr1 + " lci=" + lci + " civic=" + civic):
281        raise Exception("Set neighbor failed")
282    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:56 ssid=\"test3\" nr=" + nr2 + " lci=" + lci + " civic=" + civic):
283        raise Exception("Set neighbor failed")
284    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:56 ssid=\"test4\" nr=" + nr2 + " lci=" + lci + " civic=" + civic):
285        raise Exception("Set neighbor failed")
286    if "OK" not in hapd.request("SET_NEIGHBOR dd:11:22:33:44:55 ssid=\"test5\" nr=" + nr3 + " lci=" + lci):
287        raise Exception("Set neighbor failed")
288
289    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\""):
290        raise Exception("Request failed")
291    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"])
292
293    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" lci"):
294        raise Exception("Request failed")
295    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"],
296                     lci=True)
297
298    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" civic"):
299        raise Exception("Request failed")
300    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"],
301                     civic=True)
302
303    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" lci civic"):
304        raise Exception("Request failed")
305    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"],
306                     lci=True, civic=True)
307
308    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\""):
309        raise Exception("Request failed")
310    check_nr_results(dev[0], ["00:11:22:33:44:56"])
311
312    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\" lci"):
313        raise Exception("Request failed")
314    check_nr_results(dev[0], ["00:11:22:33:44:56"], lci=True)
315
316    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\" civic"):
317        raise Exception("Request failed")
318    check_nr_results(dev[0], ["00:11:22:33:44:56"], civic=True)
319
320    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\" lci civic"):
321        raise Exception("Request failed")
322    check_nr_results(dev[0], ["00:11:22:33:44:56"], lci=True, civic=True)
323
324    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\""):
325        raise Exception("Request failed")
326    check_nr_results(dev[0], ["dd:11:22:33:44:55"])
327
328    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\" lci"):
329        raise Exception("Request failed")
330    check_nr_results(dev[0], ["dd:11:22:33:44:55"], lci=True)
331
332    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\" civic"):
333        raise Exception("Request failed")
334    check_nr_results(dev[0], ["dd:11:22:33:44:55"])
335
336    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\" lci civic"):
337        raise Exception("Request failed")
338    check_nr_results(dev[0], ["dd:11:22:33:44:55"], lci=True)
339
340    if "OK" not in hapd.request("UPDATE_BEACON"):
341        raise Exception("UPDATE_BEACON failed")
342    time.sleep(0.2)
343    dev[1].connect("test2", key_mgmt="NONE", scan_freq="2412")
344
345def test_rrm_neighbor_rep_oom(dev, apdev):
346    """hostapd neighbor report OOM"""
347    check_rrm_support(dev[0])
348
349    nr1 = "00112233445500000000510107"
350    nr2 = "00112233445600000000510107"
351    nr3 = "dd112233445500000000510107"
352
353    params = {"ssid": "test", "rrm_neighbor_report": "1"}
354    hapd = hostapd.add_ap(apdev[0], params)
355
356    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
357
358    with alloc_fail(hapd, 1, "hostapd_send_nei_report_resp"):
359        if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
360            raise Exception("Request failed")
361        ev = dev[0].wait_event(["RRM-NEIGHBOR-REP-REQUEST-FAILED"], timeout=5)
362        if ev is None:
363            raise Exception("Neighbor report failure not reported")
364
365def test_rrm_lci_req(dev, apdev):
366    """hostapd lci request"""
367    check_rrm_support(dev[0])
368
369    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
370    hapd = hostapd.add_ap(apdev[0], params)
371
372    # station not specified
373    if "FAIL" not in hapd.request("REQ_LCI "):
374        raise Exception("REQ_LCI with no station succeeded unexpectedly")
375
376    # station that is not connected specified
377    if "FAIL" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
378        raise Exception("REQ_LCI succeeded unexpectedly (station not connected)")
379
380    dev[0].request("SET LCI ")
381    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
382
383    # station connected without LCI
384    if "FAIL" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
385        raise Exception("REQ_LCI succeeded unexpectedly (station without lci)")
386
387    dev[0].request("DISCONNECT")
388    dev[0].wait_disconnected(timeout=2)
389
390    dev[0].request("SET LCI " + lci)
391
392    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
393
394    # station connected with LCI
395    if "OK" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
396        raise Exception("REQ_LCI failed unexpectedly")
397
398def test_rrm_lci_req_timeout(dev, apdev):
399    """hostapd lci request timeout"""
400    check_rrm_support(dev[0])
401
402    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
403    hapd = hostapd.add_ap(apdev[0], params)
404
405    dev[0].request("SET LCI " + lci)
406    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
407    addr = dev[0].own_addr()
408
409    hapd.set("ext_mgmt_frame_handling", "1")
410    if "OK" not in hapd.request("REQ_LCI " + addr):
411        raise Exception("REQ_LCI failed unexpectedly")
412    ev = hapd.wait_event(["MGMT-RX"], timeout=5)
413    if ev is None:
414        raise Exception("No response seen at the AP")
415    # Ignore response and wait for HOSTAPD_RRM_REQUEST_TIMEOUT
416    time.sleep(5.1)
417    # Process response after timeout
418    if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % ev.split(' ')[1]):
419        raise Exception("MGMT_RX_PROCESS failed")
420    for i in range(257):
421        if "OK" not in hapd.request("REQ_LCI " + addr):
422            raise Exception("REQ_LCI failed unexpectedly")
423        dev[0].dump_monitor()
424        hapd.dump_monitor()
425    hapd.set("ext_mgmt_frame_handling", "0")
426    dev[0].request("DISCONNECT")
427    dev[0].wait_disconnected()
428
429def test_rrm_lci_req_oom(dev, apdev):
430    """LCI report generation OOM"""
431    check_rrm_support(dev[0])
432
433    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
434    hapd = hostapd.add_ap(apdev[0], params)
435
436    dev[0].request("SET LCI " + lci)
437    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
438
439    with alloc_fail(dev[0], 1, "wpabuf_resize;wpas_rrm_build_lci_report"):
440        if "OK" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
441            raise Exception("REQ_LCI failed unexpectedly")
442        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
443
444    dev[0].request("SET LCI ")
445    # This in in wpas_rrm_build_lci_report(), but backtrace may not always work
446    # for the "reject" label there.
447    with alloc_fail(dev[0], 1, "wpabuf_resize;wpas_rrm_handle_msr_req_element"):
448        if "OK" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
449            raise Exception("REQ_LCI failed unexpectedly")
450        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
451
452def test_rrm_lci_req_ap_oom(dev, apdev):
453    """LCI report generation AP OOM and failure"""
454    check_rrm_support(dev[0])
455
456    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
457    hapd = hostapd.add_ap(apdev[0], params)
458
459    dev[0].request("SET LCI " + lci)
460    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
461
462    with alloc_fail(hapd, 1, "wpabuf_alloc;hostapd_send_lci_req"):
463        if "FAIL" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
464            raise Exception("REQ_LCI succeeded during OOM")
465
466    with fail_test(hapd, 1, "nl80211_send_frame_cmd;hostapd_send_lci_req"):
467        if "FAIL" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
468            raise Exception("REQ_LCI succeeded during failure testing")
469
470def test_rrm_lci_req_get_reltime_failure(dev, apdev):
471    """LCI report generation and os_get_reltime() failure"""
472    check_rrm_support(dev[0])
473
474    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
475    hapd = hostapd.add_ap(apdev[0], params)
476
477    dev[0].request("SET LCI " + lci)
478    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
479
480    with fail_test(dev[0], 1, "os_get_reltime;wpas_rrm_build_lci_report"):
481        if "OK" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
482            raise Exception("REQ_LCI failed unexpectedly")
483        wait_fail_trigger(dev[0], "GET_FAIL")
484
485def test_rrm_neighbor_rep_req_from_conf(dev, apdev):
486    """wpa_supplicant ctrl_iface NEIGHBOR_REP_REQUEST and hostapd config"""
487    check_rrm_support(dev[0])
488
489    params = {"ssid": "test2", "rrm_neighbor_report": "1",
490              "stationary_ap": "1", "lci": lci, "civic": civic}
491    hapd = hostapd.add_ap(apdev[0], params)
492
493    bssid = apdev[0]['bssid']
494
495    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
496
497    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
498        raise Exception("Request failed")
499    check_nr_results(dev[0], [bssid])
500
501def test_rrm_neighbor_rep_req_timeout(dev, apdev):
502    """wpa_supplicant behavior on NEIGHBOR_REP_REQUEST response timeout"""
503    check_rrm_support(dev[0])
504
505    params = {"ssid": "test2", "rrm_neighbor_report": "1",
506              "stationary_ap": "1", "lci": lci, "civic": civic}
507    hapd = hostapd.add_ap(apdev[0], params)
508
509    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
510
511    hapd.set("ext_mgmt_frame_handling", "1")
512
513    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
514        raise Exception("Request failed")
515    msg = hapd.mgmt_rx()
516    if msg is None:
517        raise Exception("Neighbor report request not seen")
518    check_nr_results(dev[0])
519
520def test_rrm_neighbor_rep_req_oom(dev, apdev):
521    """wpa_supplicant ctrl_iface NEIGHBOR_REP_REQUEST OOM"""
522    check_rrm_support(dev[0])
523
524    params = {"ssid": "test2", "rrm_neighbor_report": "1",
525              "stationary_ap": "1", "lci": lci, "civic": civic}
526    hapd = hostapd.add_ap(apdev[0], params)
527
528    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
529
530    with alloc_fail(dev[0], 1, "wpabuf_alloc;wpas_rrm_process_neighbor_rep"):
531        if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
532            raise Exception("Request failed")
533        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
534
535    with fail_test(dev[0], 1,
536                    "wpa_driver_nl80211_send_action;wpas_rrm_send_neighbor_rep_request"):
537        if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
538            raise Exception("Request succeeded unexpectedly")
539
540    with alloc_fail(dev[0], 1,
541                    "wpabuf_alloc;wpas_rrm_send_neighbor_rep_request"):
542        if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
543            raise Exception("Request succeeded unexpectedly")
544
545def test_rrm_neighbor_rep_req_disconnect(dev, apdev):
546    """wpa_supplicant behavior on disconnection during NEIGHBOR_REP_REQUEST"""
547    check_rrm_support(dev[0])
548
549    params = {"ssid": "test2", "rrm_neighbor_report": "1",
550              "stationary_ap": "1", "lci": lci, "civic": civic}
551    hapd = hostapd.add_ap(apdev[0], params)
552
553    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
554        raise Exception("Request accepted while disconnected")
555
556    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
557
558    hapd.set("ext_mgmt_frame_handling", "1")
559
560    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
561        raise Exception("Request failed")
562    msg = hapd.mgmt_rx()
563    if msg is None:
564        raise Exception("Neighbor report request not seen")
565    dev[0].request("DISCONNECT")
566    check_nr_results(dev[0])
567
568def test_rrm_neighbor_rep_req_not_supported(dev, apdev):
569    """NEIGHBOR_REP_REQUEST for AP not supporting neighbor report"""
570    check_rrm_support(dev[0])
571
572    params = {"ssid": "test2", "rrm_beacon_report": "1"}
573    hapd = hostapd.add_ap(apdev[0], params)
574
575    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
576
577    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
578        raise Exception("Request accepted unexpectedly")
579
580def test_rrm_neighbor_rep_req_busy(dev, apdev):
581    """wpa_supplicant and concurrent NEIGHBOR_REP_REQUEST commands"""
582    check_rrm_support(dev[0])
583
584    params = {"ssid": "test2", "rrm_neighbor_report": "1",
585              "stationary_ap": "1", "lci": lci, "civic": civic}
586    hapd = hostapd.add_ap(apdev[0], params)
587
588    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
589
590    hapd.set("ext_mgmt_frame_handling", "1")
591
592    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
593        raise Exception("Request failed")
594    msg = hapd.mgmt_rx()
595    if msg is None:
596        raise Exception("Neighbor report request not seen")
597
598    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
599        raise Exception("Request accepted while disconnected")
600
601def test_rrm_ftm_range_req(dev, apdev):
602    """hostapd FTM range request command"""
603    check_rrm_support(dev[0])
604    try:
605        run_rrm_ftm_range_req(dev, apdev)
606    finally:
607        dev[1].request("VENDOR_ELEM_REMOVE 13 *")
608
609def run_rrm_ftm_range_req(dev, apdev):
610    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
611    hapd = hostapd.add_ap(apdev[0], params)
612    bssid = hapd.own_addr()
613
614    # station not specified
615    if "FAIL" not in hapd.request("REQ_RANGE "):
616        raise Exception("REQ_RANGE with no station succeeded unexpectedly")
617
618    # station that is not connected specified
619    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr()):
620        raise Exception("REQ_RANGE succeeded unexpectedly (station not connected)")
621
622    # No responders specified
623    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10"):
624        raise Exception("REQ_RANGE succeeded unexpectedly (no responder)")
625
626    # Bad responder address
627    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10 00:11:22:33:44:"):
628        raise Exception("REQ_RANGE succeeded unexpectedly (bad responder address)")
629
630    # Bad responder address
631    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10 00:11:22:33:44:55 00:11:22:33:44"):
632        raise Exception("REQ_RANGE succeeded unexpectedly (bad responder address 2)")
633
634    # Bad min_ap value
635    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 300 00:11:22:33:44:55"):
636        raise Exception("REQ_RANGE succeeded unexpectedly (invalid min_ap value)")
637
638    # Bad rand value
639    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " -1 10 00:11:22:33:44:55"):
640        raise Exception("REQ_RANGE succeeded unexpectedly (invalid rand value)")
641    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 65536 10 00:11:22:33:44:55"):
642        raise Exception("REQ_RANGE succeeded unexpectedly (invalid rand value)")
643
644    # Missing min_ap value
645    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10"):
646        raise Exception("REQ_RANGE succeeded unexpectedly (missing min_ap value)")
647
648    # Too many responders
649    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10" + 20*" 00:11:22:33:44:55"):
650        raise Exception("REQ_RANGE succeeded unexpectedly (too many responders)")
651    # Wrong min AP count
652    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10 00:11:22:33:44:55"):
653        raise Exception("REQ_RANGE succeeded unexpectedly (responder not in database)")
654
655    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
656    # Override RM capabilities to include FTM range report
657    dev[1].request("VENDOR_ELEM_ADD 13 46057100000004")
658    dev[1].connect("rrm", key_mgmt="NONE", scan_freq="2412")
659
660    # Request range: Destination address is not connected
661    if "FAIL" not in hapd.request("REQ_RANGE 11:22:33:44:55:66 10 1 00:11:22:33:44:55"):
662        raise Exception("REQ_RANGE succeeded unexpectedly (responder not in database)")
663
664    # Responder not in database
665    # Note: this check would pass since the station does not support FTM range
666    # request and not because the responder is not in the database.
667    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 1 00:11:22:33:44:55"):
668        raise Exception("REQ_RANGE succeeded unexpectedly (responder not in database)")
669
670    # Missing neighbor report for 00:11:22:33:44:55
671    if "FAIL" not in hapd.request("REQ_RANGE " + dev[1].own_addr() + " 10 1 00:11:22:33:44:55"):
672        raise Exception("REQ_RANGE succeeded unexpectedly (responder not in database)")
673
674    # Send request
675    if "OK" not in hapd.request("REQ_RANGE " + dev[1].own_addr() + " 10 1 " + bssid):
676        raise Exception("REQ_RANGE failed unexpectedly")
677
678    # Too long range request
679    if "FAIL" not in hapd.request("REQ_RANGE " + dev[1].own_addr() + " 10 1" + 16*(" " + bssid)):
680        raise Exception("REQ_RANGE accepted for too long range request")
681
682    time.sleep(0.1)
683    dev[0].request("DISCONNECT")
684    dev[1].request("DISCONNECT")
685    dev[1].wait_disconnected()
686
687def test_rrm_ftm_range_req_timeout(dev, apdev):
688    """hostapd FTM range request timeout"""
689    check_rrm_support(dev[0])
690    try:
691        run_rrm_ftm_range_req_timeout(dev, apdev)
692    finally:
693        dev[1].request("VENDOR_ELEM_REMOVE 13 *")
694
695def run_rrm_ftm_range_req_timeout(dev, apdev):
696    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
697    hapd = hostapd.add_ap(apdev[0], params)
698    bssid = hapd.own_addr()
699
700    # Override RM capabilities to include FTM range report
701    dev[1].request("VENDOR_ELEM_ADD 13 46057100000004")
702    dev[1].connect("rrm", key_mgmt="NONE", scan_freq="2412")
703    addr = dev[1].own_addr()
704
705    hapd.set("ext_mgmt_frame_handling", "1")
706    if "OK" not in hapd.request("REQ_RANGE " + addr + " 10 1 " + bssid):
707        raise Exception("REQ_RANGE failed")
708    ev = hapd.wait_event(["MGMT-RX"], timeout=5)
709    if ev is None:
710        raise Exception("No response seen at the AP")
711    # Ignore response and wait for HOSTAPD_RRM_REQUEST_TIMEOUT
712    time.sleep(5.1)
713    # Process response after timeout
714    if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % ev.split(' ')[1]):
715        raise Exception("MGMT_RX_PROCESS failed")
716
717    for i in range(257):
718        if "OK" not in hapd.request("REQ_RANGE " + addr + " 10 1 " + bssid):
719            raise Exception("REQ_RANGE failed")
720        dev[1].dump_monitor()
721        hapd.dump_monitor()
722
723    hapd.set("ext_mgmt_frame_handling", "0")
724    dev[1].request("DISCONNECT")
725    dev[1].wait_disconnected()
726
727def test_rrm_ftm_range_req_failure(dev, apdev):
728    """hostapd FTM range request failure"""
729    check_rrm_support(dev[0])
730    try:
731        run_rrm_ftm_range_req_failure(dev, apdev)
732    finally:
733        dev[1].request("VENDOR_ELEM_REMOVE 13 *")
734
735def run_rrm_ftm_range_req_failure(dev, apdev):
736    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
737    hapd = hostapd.add_ap(apdev[0], params)
738    bssid = hapd.own_addr()
739
740    # Override RM capabilities to include FTM range report
741    dev[1].request("VENDOR_ELEM_ADD 13 46057100000004")
742    dev[1].connect("rrm", key_mgmt="NONE", scan_freq="2412")
743
744    with alloc_fail(hapd, 1, "wpabuf_alloc;hostapd_send_range_req"):
745        if "FAIL" not in hapd.request("REQ_RANGE " + dev[1].own_addr() + " 10 1 " + bssid):
746            raise Exception("REQ_RANGE succeeded during OOM")
747
748    with fail_test(hapd, 1, "nl80211_send_frame_cmd;hostapd_send_range_req"):
749        if "FAIL" not in hapd.request("REQ_RANGE " + dev[1].own_addr() + " 10 1 " + bssid):
750            raise Exception("REQ_RANGE succeeded during failure testing")
751
752    dev[1].request("DISCONNECT")
753    dev[1].wait_disconnected()
754
755def test_rrm_ftm_capa_indication(dev, apdev):
756    """FTM capability indication"""
757    try:
758        _test_rrm_ftm_capa_indication(dev, apdev)
759    finally:
760        dev[0].request("SET ftm_initiator 0")
761        dev[0].request("SET ftm_responder 0")
762
763def _test_rrm_ftm_capa_indication(dev, apdev):
764    params = {"ssid": "ftm",
765              "ftm_responder": "1",
766              "ftm_initiator": "1",}
767    hapd = hostapd.add_ap(apdev[0], params)
768
769    if "OK" not in dev[0].request("SET ftm_initiator 1"):
770        raise Exception("could not set ftm_initiator")
771    if "OK" not in dev[0].request("SET ftm_responder 1"):
772        raise Exception("could not set ftm_responder")
773    dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412, force_scan=True)
774
775class BeaconReport:
776    def __init__(self, report):
777        self.opclass, self.channel, self.start, self.duration, self.frame_info, self.rcpi, self.rsni = struct.unpack("<BBQHBBB", report[0:15])
778        report = report[15:]
779        self.bssid = report[0:6]
780        self.bssid_str = "%02x:%02x:%02x:%02x:%02x:%02x" % (struct.unpack('6B', self.bssid))
781        report = report[6:]
782        self.antenna_id, self.parent_tsf = struct.unpack("<BI", report[0:5])
783        report = report[5:]
784        self.subelems = report
785        self.frame_body = None
786        self.frame_body_fragment_id = None
787        self.last_indication = None
788        while len(report) >= 2:
789            eid, elen = struct.unpack('BB', report[0:2])
790            report = report[2:]
791            if len(report) < elen:
792                raise Exception("Invalid subelement in beacon report")
793            if eid == 1:
794                # Reported Frame Body
795                # Contents depends on the reporting detail request:
796                # 0 = no Reported Frame Body subelement
797                # 1 = all fixed fields and any elements identified in Request
798                #     element
799                # 2 = all fixed fields and all elements
800                # Fixed fields: Timestamp[8] BeaconInt[2] CapabInfo[2]
801                self.frame_body = report[0:elen]
802            if eid == 2:
803                self.frame_body_fragment_id = report[0:elen]
804            if eid == 164:
805                self.last_indication = report[0:elen]
806            report = report[elen:]
807    def __str__(self):
808        txt = "opclass={} channel={} start={} duration={} frame_info={} rcpi={} rsni={} bssid={} antenna_id={} parent_tsf={}".format(self.opclass, self.channel, self.start, self.duration, self.frame_info, self.rcpi, self.rsni, self.bssid_str, self.antenna_id, self.parent_tsf)
809        if self.frame_body:
810            txt += " frame_body=" + binascii.hexlify(self.frame_body).decode()
811        if self.frame_body_fragment_id:
812            txt += " fragment_id=" + binascii.hexlify(self.frame_body_fragment_id).decode()
813        if self.last_indication:
814            txt += " last_indication=" + binascii.hexlify(self.last_indication).decode()
815
816        return txt
817
818def build_beacon_request(opclass=81, chan=0, rand_int=0, duration=0, mode=0,
819                         bssid="FF:FF:FF:FF:FF:FF"):
820    req = struct.pack("<BBHHB", opclass, chan, rand_int, duration, mode)
821    return binascii.hexlify(req).decode() + bssid.replace(':', '')
822
823def run_req_beacon(hapd, addr, request):
824    token = hapd.request("REQ_BEACON " + addr + " " + request)
825    if "FAIL" in token:
826        raise Exception("REQ_BEACON failed")
827
828    resp = []
829    for i in range(10):
830        ev = hapd.wait_event(["BEACON-REQ-TX-STATUS",
831                              "BEACON-RESP-RX"], timeout=5)
832        if ev is None:
833            raise Exception("No TX status event for beacon request received")
834        if "BEACON-REQ-TX-STATUS" in ev:
835            break
836        resp.append(ev)
837    else:
838        raise Exception("No TX status event for beacon request received")
839    fields = ev.split(' ')
840    if fields[1] != addr:
841        raise Exception("Unexpected STA address in TX status: " + fields[1])
842    if fields[2] != token:
843        raise Exception("Unexpected dialog token in TX status: " + fields[2] + " (expected " + token + ")")
844    if fields[3] != "ack=1":
845        raise Exception("Unexected ACK status in TX status: " + fields[3])
846    return token, resp
847
848@remote_compatible
849def test_rrm_beacon_req_table(dev, apdev):
850    """Beacon request - beacon table mode"""
851    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
852    hapd = hostapd.add_ap(apdev[0], params)
853    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another"})
854
855    tests = ["REQ_BEACON ",
856             "REQ_BEACON q",
857             "REQ_BEACON 11:22:33:44:55:66",
858             "REQ_BEACON 11:22:33:44:55:66 req_mode=q",
859             "REQ_BEACON 11:22:33:44:55:66 req_mode=11",
860             "REQ_BEACON 11:22:33:44:55:66 1",
861             "REQ_BEACON 11:22:33:44:55:66 1q",
862             "REQ_BEACON 11:22:33:44:55:66 11223344556677889900aabbccddeeff"]
863    for t in tests:
864        if "FAIL" not in hapd.request(t):
865            raise Exception("Invalid command accepted: " + t)
866
867    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2412)
868    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
869    addr = dev[0].own_addr()
870    hapd.wait_sta()
871
872    req = build_beacon_request(mode=2)
873    token, resp = run_req_beacon(hapd, addr, req)
874
875    for i in range(1, 3):
876        if resp:
877            ev = resp.pop(0)
878        else:
879            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
880        if ev is None:
881            raise Exception("Beacon report %d response not received" % i)
882        fields = ev.split(' ')
883        if fields[1] != addr:
884            raise Exception("Unexpected STA address in beacon report response: " + fields[1])
885        if fields[2] != token:
886            raise Exception("Unexpected dialog token in beacon report response: " + fields[2] + " (expected " + token + ")")
887        if fields[3] != "00":
888            raise Exception("Unexpected measurement report mode")
889
890        report = BeaconReport(binascii.unhexlify(fields[4]))
891        logger.info("Received beacon report: " + str(report))
892
893        # Default reporting detail is 2, i.e., all fixed fields and elements.
894        if not report.frame_body:
895            raise Exception("Reported Frame Body subelement missing")
896        if len(report.frame_body) <= 12:
897            raise Exception("Too short Reported Frame Body subelement")
898
899def test_rrm_beacon_req_frame_body_fragmentation(dev, apdev):
900    """Beacon request - beacon table mode - frame body fragmentation"""
901    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
902
903    hapd = hostapd.add_ap(apdev[0], params)
904    hapd.set('vendor_elements', ("dd051122330203dd0400137400dd04001374ffdd0511"
905              "22330203dd0400137400dd04001374ffdd051122330203dd0400137400dd04001"
906              "374ffdd051122330203dd0400137400dd04001374ffdd051122330203dd040013"
907              "7400dd04001374ffdd051122330203dd0400137400dd04001374ffdd051122330"
908              "203dd0400137400dd04001374ffdd051122330203dd0400137400dd04001374ff"
909              "dd051122330203dd0400137400dd04001374ff"))
910
911    dev[0].flush_scan_cache()
912    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
913    addr = dev[0].own_addr()
914    hapd.wait_sta()
915
916    req = build_beacon_request(mode=2)
917    token, resp = run_req_beacon(hapd, addr, req)
918
919    # 2 beacon reports elements are expected because of fragmentation
920    for i in range(0, 2):
921        if resp:
922            ev = resp.pop(0)
923        else:
924            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
925        if ev is None:
926            raise Exception("Beacon report %d response not received" % i)
927        fields = ev.split(' ')
928        if fields[1] != addr:
929            raise Exception("Unexpected STA address in beacon report response: " + fields[1])
930        if fields[2] != token:
931            raise Exception("Unexpected dialog token in beacon report response: " + fields[2] + " (expected " + token + ")")
932        if fields[3] != "00":
933            raise Exception("Unexpected measurement report mode")
934
935        report = BeaconReport(binascii.unhexlify(fields[4]))
936        logger.info("Received beacon report: " + str(report))
937
938        # Default reporting detail is 2, i.e., all fixed fields and elements.
939        if not report.frame_body_fragment_id:
940            raise Exception("Reported Frame Body Fragment ID subelement missing")
941        fragment_id = binascii.hexlify(report.frame_body_fragment_id)
942        frag_number = int(fragment_id[2:], 16) & int(0x7f)
943        if frag_number != i:
944            raise Exception("Incorrect fragment number: %d" % frag_number)
945        more_frags = int(fragment_id[2:], 16) >> 7
946        if i == 0 and more_frags != 1:
947            raise Exception("more fragments bit is not set on first fragment")
948        if i == 1 and more_frags != 0:
949            raise Exception("more fragments bit is set on last fragment")
950
951def test_rrm_beacon_req_last_frame_indication(dev, apdev):
952    """Beacon request - beacon table mode - last frame indication"""
953    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
954
955    hapd = hostapd.add_ap(apdev[0], params)
956    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another"})
957
958    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
959    addr = dev[0].own_addr()
960    hapd.wait_sta()
961
962    # The request contains the last beacon report indication subelement
963    req = build_beacon_request(mode=2)
964    token, resp = run_req_beacon(hapd, addr, req + "a40101")
965
966    for i in range(1, 3):
967        if resp:
968            ev = resp.pop(0)
969        else:
970            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
971        if ev is None:
972            raise Exception("Beacon report %d response not received" % i)
973        fields = ev.split(' ')
974        if fields[1] != addr:
975            raise Exception("Unexpected STA address in beacon report response: " + fields[1])
976        if fields[2] != token:
977            raise Exception("Unexpected dialog token in beacon report response: " + fields[2] + " (expected " + token + ")")
978        if fields[3] != "00":
979            raise Exception("Unexpected measurement report mode")
980
981        report = BeaconReport(binascii.unhexlify(fields[4]))
982        logger.info("Received beacon report: " + str(report))
983
984        if not report.last_indication:
985            raise Exception("Last Beacon Report Indication subelement missing")
986
987        last = binascii.hexlify(report.last_indication).decode()
988        if (i == 2 and last != '01') or (i != 2 and last != '00'):
989            raise Exception("last beacon report indication is not set on last frame")
990
991    # The request does not contain the last beacon report indication subelement
992    req = build_beacon_request(mode=2)
993    token, resp = run_req_beacon(hapd, addr, req)
994
995    for i in range(1, 3):
996        if resp:
997            ev = resp.pop(0)
998        else:
999            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1000        if ev is None:
1001            raise Exception("Beacon report %d response not received" % i)
1002        fields = ev.split(' ')
1003        if fields[1] != addr:
1004            raise Exception("Unexpected STA address in beacon report response: " + fields[1])
1005        if fields[2] != token:
1006            raise Exception("Unexpected dialog token in beacon report response: " + fields[2] + " (expected " + token + ")")
1007        if fields[3] != "00":
1008            raise Exception("Unexpected measurement report mode")
1009
1010        report = BeaconReport(binascii.unhexlify(fields[4]))
1011        logger.info("Received beacon report: " + str(report))
1012
1013        if report.last_indication:
1014            raise Exception("Last Beacon Report Indication subelement present but not requested")
1015
1016@remote_compatible
1017def test_rrm_beacon_req_table_detail(dev, apdev):
1018    """Beacon request - beacon table mode - reporting detail"""
1019    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1020    hapd = hostapd.add_ap(apdev[0], params)
1021
1022    dev[0].flush_scan_cache()
1023    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1024    addr = dev[0].own_addr()
1025    hapd.wait_sta()
1026
1027    logger.info("Reporting Detail 0")
1028    req = build_beacon_request(mode=2)
1029    token, resp = run_req_beacon(hapd, addr, req + "020100")
1030    if resp:
1031        ev = resp.pop(0)
1032    else:
1033        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1034    if ev is None:
1035        raise Exception("Beacon report response not received")
1036    fields = ev.split(' ')
1037    report = BeaconReport(binascii.unhexlify(fields[4]))
1038    logger.info("Received beacon report: " + str(report))
1039    if report.frame_body:
1040        raise Exception("Reported Frame Body subelement included with Reporting Detail 0")
1041    hapd.dump_monitor()
1042
1043    logger.info("Reporting Detail 1")
1044    token, resp = run_req_beacon(hapd, addr, req + "020101")
1045    if resp:
1046        ev = resp.pop(0)
1047    else:
1048        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1049    if ev is None:
1050        raise Exception("Beacon report response not received")
1051    fields = ev.split(' ')
1052    report = BeaconReport(binascii.unhexlify(fields[4]))
1053    logger.info("Received beacon report: " + str(report))
1054    if not report.frame_body:
1055        raise Exception("Reported Frame Body subelement missing")
1056    if len(report.frame_body) != 12:
1057        raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 1")
1058    hapd.dump_monitor()
1059
1060    logger.info("Reporting Detail 2")
1061    token, resp = run_req_beacon(hapd, addr, req + "020102")
1062    if resp:
1063        ev = resp.pop(0)
1064    else:
1065        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1066    if ev is None:
1067        raise Exception("Beacon report response not received")
1068    fields = ev.split(' ')
1069    report = BeaconReport(binascii.unhexlify(fields[4]))
1070    logger.info("Received beacon report: " + str(report))
1071    if not report.frame_body:
1072        raise Exception("Reported Frame Body subelement missing")
1073    if len(report.frame_body) <= 12:
1074        raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 2")
1075    hapd.dump_monitor()
1076
1077    logger.info("Reporting Detail 3 (invalid)")
1078    token, resp = run_req_beacon(hapd, addr, req + "020103")
1079    if resp:
1080        ev = resp.pop(0)
1081    else:
1082        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1083    if ev is not None:
1084        raise Exception("Unexpected beacon report response to invalid reporting detail 3")
1085    hapd.dump_monitor()
1086
1087    logger.info("Reporting Detail (too short)")
1088    token, resp = run_req_beacon(hapd, addr, req + "0200")
1089    if resp:
1090        ev = resp.pop(0)
1091    else:
1092        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1093    if ev is not None:
1094        raise Exception("Unexpected beacon report response to invalid reporting detail")
1095    hapd.dump_monitor()
1096
1097@remote_compatible
1098def test_rrm_beacon_req_table_request(dev, apdev):
1099    """Beacon request - beacon table mode - request element"""
1100    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1101    hapd = hostapd.add_ap(apdev[0], params)
1102
1103    dev[0].flush_scan_cache()
1104    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1105    addr = dev[0].own_addr()
1106    hapd.wait_sta()
1107
1108    req = build_beacon_request(mode=2)
1109    token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a03000106")
1110    if resp:
1111        ev = resp.pop(0)
1112    else:
1113        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1114    if ev is None:
1115        raise Exception("Beacon report response not received")
1116    fields = ev.split(' ')
1117    report = BeaconReport(binascii.unhexlify(fields[4]))
1118    logger.info("Received beacon report: " + str(report))
1119    if not report.frame_body:
1120        raise Exception("Reported Frame Body subelement missing")
1121    if len(report.frame_body) != 12 + 5 + 10:
1122        raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 1 and requested elements SSID + SuppRates")
1123    hapd.dump_monitor()
1124
1125    logger.info("Incorrect reporting detail with request subelement")
1126    token, resp = run_req_beacon(hapd, addr, req + "020102" + "0a03000106")
1127    if resp:
1128        ev = resp.pop(0)
1129    else:
1130        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1131    if ev is not None:
1132        raise Exception("Unexpected beacon report response (invalid reporting detail)")
1133    hapd.dump_monitor()
1134
1135    logger.info("Invalid request subelement length")
1136    token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a00")
1137    if resp:
1138        ev = resp.pop(0)
1139    else:
1140        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1141    if ev is not None:
1142        raise Exception("Unexpected beacon report response (invalid request subelement length)")
1143    hapd.dump_monitor()
1144
1145    logger.info("Multiple request subelements")
1146    token, resp = run_req_beacon(hapd, addr,
1147                                 req + "020101" + "0a0100" + "0a0101")
1148    if resp:
1149        ev = resp.pop(0)
1150    else:
1151        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1152    if ev is not None:
1153        raise Exception("Unexpected beacon report response (multiple request subelements)")
1154    hapd.dump_monitor()
1155
1156@remote_compatible
1157def test_rrm_beacon_req_table_request_oom(dev, apdev):
1158    """Beacon request - beacon table mode - request element OOM"""
1159    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1160    hapd = hostapd.add_ap(apdev[0], params)
1161
1162    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1163    addr = dev[0].own_addr()
1164    hapd.wait_sta()
1165
1166    req = build_beacon_request(mode=2)
1167    with alloc_fail(dev[0], 1,
1168                    "bitfield_alloc;wpas_rm_handle_beacon_req_subelem"):
1169        token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a03000106")
1170        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1171        if resp:
1172            ev = resp.pop(0)
1173        else:
1174            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
1175        if ev is not None:
1176            raise Exception("Unexpected beacon report response received (OOM)")
1177
1178    with alloc_fail(dev[0], 1,
1179                    "wpabuf_alloc;wpas_rrm_send_msr_report_mpdu"):
1180        token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a03000106")
1181        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1182        if resp:
1183            ev = resp.pop(0)
1184        else:
1185            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
1186        if ev is not None:
1187            raise Exception("Unexpected beacon report response received (OOM)")
1188
1189    with fail_test(dev[0], 1,
1190                    "wpa_driver_nl80211_send_action;wpas_rrm_send_msr_report_mpdu"):
1191        token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a03000106")
1192        wait_fail_trigger(dev[0], "GET_FAIL")
1193        if resp:
1194            ev = resp.pop(0)
1195        else:
1196            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
1197        if ev is not None:
1198            raise Exception("Unexpected beacon report response received (OOM)")
1199
1200    with alloc_fail(dev[0], 1,
1201                    "wpabuf_resize;wpas_add_beacon_rep"):
1202        token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a03000106")
1203        if resp:
1204            ev = resp.pop(0)
1205        else:
1206            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1207        if ev is None:
1208            raise Exception("Beacon report response not received (OOM -> empty report)")
1209        fields = ev.split(' ')
1210        if len(fields[4]) > 0:
1211            raise Exception("Unexpected beacon report received")
1212
1213@remote_compatible
1214def test_rrm_beacon_req_table_bssid(dev, apdev):
1215    """Beacon request - beacon table mode - specific BSSID"""
1216    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1217    hapd = hostapd.add_ap(apdev[0], params)
1218    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another"})
1219
1220    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1221    addr = dev[0].own_addr()
1222    hapd.wait_sta()
1223
1224    bssid2 = hapd2.own_addr()
1225    req = build_beacon_request(mode=2, bssid=bssid2)
1226    token, resp = run_req_beacon(hapd, addr, req)
1227    if resp:
1228        ev = resp.pop(0)
1229    else:
1230        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1231    if ev is None:
1232        raise Exception("Beacon report response not received")
1233    fields = ev.split(' ')
1234    report = BeaconReport(binascii.unhexlify(fields[4]))
1235    logger.info("Received beacon report: " + str(report))
1236    if "bssid=" + bssid2 not in str(report):
1237        raise Exception("Report for unexpected BSS")
1238    if resp:
1239        ev = resp.pop(0)
1240    else:
1241        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
1242    if ev is not None:
1243        raise Exception("Unexpected beacon report response")
1244
1245@remote_compatible
1246def test_rrm_beacon_req_table_ssid(dev, apdev):
1247    """Beacon request - beacon table mode - specific SSID"""
1248    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1249    hapd = hostapd.add_ap(apdev[0], params)
1250    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another"})
1251
1252    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1253    addr = dev[0].own_addr()
1254    hapd.wait_sta()
1255
1256    bssid2 = hapd2.own_addr()
1257    req = build_beacon_request(mode=2)
1258    token, resp = run_req_beacon(hapd, addr, req + "0007" + binascii.hexlify(b"another").decode())
1259    if resp:
1260        ev = resp.pop(0)
1261    else:
1262        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1263    if ev is None:
1264        raise Exception("Beacon report response not received")
1265    fields = ev.split(' ')
1266    report = BeaconReport(binascii.unhexlify(fields[4]))
1267    logger.info("Received beacon report: " + str(report))
1268    if "bssid=" + bssid2 not in str(report):
1269        raise Exception("Report for unexpected BSS")
1270    if resp:
1271        ev = resp.pop(0)
1272    else:
1273        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
1274    if ev is not None:
1275        raise Exception("Unexpected beacon report response")
1276    hapd.dump_monitor()
1277
1278    logger.info("Wildcard SSID")
1279    token, resp = run_req_beacon(hapd, addr, req + "0000")
1280    for i in range(2):
1281        if resp:
1282            ev = resp.pop(0)
1283        else:
1284            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1285        if ev is None:
1286            raise Exception("Beacon report response not received")
1287        fields = ev.split(' ')
1288        report = BeaconReport(binascii.unhexlify(fields[4]))
1289        logger.info("Received beacon report: " + str(report))
1290    hapd.dump_monitor()
1291
1292    logger.info("Too long SSID")
1293    token, resp = run_req_beacon(hapd, addr, req + "0021" + 33*"00")
1294    if resp:
1295        ev = resp.pop(0)
1296    else:
1297        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1298    if ev is not None:
1299        raise Exception("Unexpected beacon report response (invalid SSID subelement in request)")
1300    hapd.dump_monitor()
1301
1302@remote_compatible
1303def test_rrm_beacon_req_table_info(dev, apdev):
1304    """Beacon request - beacon table mode - Reporting Information subelement"""
1305    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1306    hapd = hostapd.add_ap(apdev[0], params)
1307
1308    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1309    addr = dev[0].own_addr()
1310    hapd.wait_sta()
1311
1312    logger.info("Unsupported reporting information 1")
1313    req = build_beacon_request(mode=2)
1314    token, resp = run_req_beacon(hapd, addr, req + "01020100")
1315    if resp:
1316        ev = resp.pop(0)
1317    else:
1318        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1319    if ev is None:
1320        raise Exception("Beacon report response (incapable) is not received")
1321
1322    fields = ev.split(' ')
1323    if fields[3] != "02":
1324        raise Exception("Beacon report response - unexpected mode (" + fields[3] + ")")
1325    hapd.dump_monitor()
1326
1327    logger.info("Invalid reporting information length")
1328    token, resp = run_req_beacon(hapd, addr, req + "010100")
1329    if resp:
1330        ev = resp.pop(0)
1331    else:
1332        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1333    if ev is not None:
1334        raise Exception("Unexpected beacon report response (invalid reporting information length)")
1335    hapd.dump_monitor()
1336
1337@remote_compatible
1338def test_rrm_beacon_req_table_unknown_subelem(dev, apdev):
1339    """Beacon request - beacon table mode - unknown subelement"""
1340    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1341    hapd = hostapd.add_ap(apdev[0], params)
1342
1343    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1344    addr = dev[0].own_addr()
1345    hapd.wait_sta()
1346
1347    req = build_beacon_request(mode=2)
1348    token, resp = run_req_beacon(hapd, addr, req + "330101" + "fe00")
1349    if resp:
1350        ev = resp.pop(0)
1351    else:
1352        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1353    if ev is None:
1354        raise Exception("Beacon report response not received")
1355    fields = ev.split(' ')
1356    report = BeaconReport(binascii.unhexlify(fields[4]))
1357    logger.info("Received beacon report: " + str(report))
1358
1359@remote_compatible
1360def test_rrm_beacon_req_table_truncated_subelem(dev, apdev):
1361    """Beacon request - beacon table mode - Truncated subelement"""
1362    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1363    hapd = hostapd.add_ap(apdev[0], params)
1364
1365    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1366    addr = dev[0].own_addr()
1367    hapd.wait_sta()
1368
1369    req = build_beacon_request(mode=2)
1370    token, resp = run_req_beacon(hapd, addr, req + "0001")
1371    if resp:
1372        ev = resp.pop(0)
1373    else:
1374        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1375    if ev is not None:
1376        raise Exception("Unexpected beacon report response (truncated subelement)")
1377    hapd.dump_monitor()
1378
1379@remote_compatible
1380def test_rrm_beacon_req_table_rsne(dev, apdev):
1381    """Beacon request - beacon table mode - RSNE reporting"""
1382    params = hostapd.wpa2_params(ssid="rrm-rsn", passphrase="12345678")
1383    params["rrm_beacon_report"] = "1"
1384    hapd = hostapd.add_ap(apdev[0], params)
1385
1386    dev[0].connect("rrm-rsn", psk="12345678", scan_freq="2412")
1387    addr = dev[0].own_addr()
1388    hapd.wait_sta()
1389
1390    req = build_beacon_request(mode=2)
1391    token, resp = run_req_beacon(hapd, addr, req + "020101" + "0a0130")
1392    if resp:
1393        ev = resp.pop(0)
1394    else:
1395        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1396    if ev is None:
1397        raise Exception("Beacon report response not received")
1398    fields = ev.split(' ')
1399    report = BeaconReport(binascii.unhexlify(fields[4]))
1400    logger.info("Received beacon report: " + str(report))
1401    if not report.frame_body:
1402        raise Exception("Reported Frame Body subelement missing")
1403    if len(report.frame_body) != 12 + 22:
1404        raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 1 and requested element RSNE")
1405    if binascii.unhexlify("30140100000fac040100000fac040100000fac020c00") not in report.frame_body:
1406        raise Exception("Full RSNE not found")
1407
1408def test_rrm_beacon_req_table_vht(dev, apdev):
1409    """Beacon request - beacon table mode - VHT"""
1410    clear_scan_cache(apdev[0])
1411    try:
1412        hapd = None
1413        params = {"ssid": "rrm-vht",
1414                  "country_code": "FI",
1415                  "hw_mode": "a",
1416                  "channel": "36",
1417                  "ht_capab": "[HT40+]",
1418                  "ieee80211n": "1",
1419                  "ieee80211ac": "1",
1420                  "vht_oper_chwidth": "1",
1421                  "vht_oper_centr_freq_seg0_idx": "42",
1422                  "rrm_beacon_report": "1"}
1423        hapd = hostapd.add_ap(apdev[0], params)
1424
1425        params = {"ssid": "test-vht40",
1426                  "country_code": "FI",
1427                  "hw_mode": "a",
1428                  "channel": "48",
1429                  "ieee80211n": "1",
1430                  "ieee80211ac": "1",
1431                  "ht_capab": "[HT40-]",
1432                  "vht_capab": "",
1433                  "vht_oper_chwidth": "0",
1434                  "vht_oper_centr_freq_seg0_idx": "0",
1435                }
1436        hapd2 = hostapd.add_ap(apdev[1], params)
1437
1438        dev[0].scan_for_bss(apdev[1]['bssid'], freq=5240)
1439        dev[0].connect("rrm-vht", key_mgmt="NONE", scan_freq="5180")
1440
1441        addr = dev[0].own_addr()
1442        hapd.wait_sta()
1443
1444        req = build_beacon_request(opclass=240, mode=2)
1445        token, resp = run_req_beacon(hapd, addr, req)
1446        for i in range(2):
1447            if resp:
1448                ev = resp.pop(0)
1449            else:
1450                ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1451            if ev is None:
1452                raise Exception("Beacon report %d response not received" % i)
1453            fields = ev.split(' ')
1454            report = BeaconReport(binascii.unhexlify(fields[4]))
1455            logger.info("Received beacon report: " + str(report))
1456            if report.bssid_str == apdev[0]['bssid']:
1457                if report.opclass != 128 or report.channel != 36:
1458                    raise Exception("Incorrect opclass/channel for AP0")
1459            elif report.bssid_str == apdev[1]['bssid']:
1460                if report.opclass != 117 or report.channel != 48:
1461                    raise Exception("Incorrect opclass/channel for AP1")
1462    except Exception as e:
1463        if isinstance(e, Exception) and str(e) == "AP startup failed":
1464            if not vht_supported():
1465                raise HwsimSkip("80 MHz channel not supported in regulatory information")
1466        raise
1467    finally:
1468        dev[0].request("DISCONNECT")
1469        disable_hapd(hapd)
1470        disable_hapd(hapd2)
1471        clear_regdom_dev(dev)
1472
1473@remote_compatible
1474def test_rrm_beacon_req_active(dev, apdev):
1475    """Beacon request - active scan mode"""
1476    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1477    hapd = hostapd.add_ap(apdev[0], params)
1478    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1479
1480    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1481    addr = dev[0].own_addr()
1482    hapd.wait_sta()
1483
1484    req = build_beacon_request(duration=100, mode=1)
1485    token, resp = run_req_beacon(hapd, addr, req)
1486
1487    for i in range(1, 3):
1488        if resp:
1489            ev = resp.pop(0)
1490        else:
1491            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1492        if ev is None:
1493            raise Exception("Beacon report %d response not received" % i)
1494        fields = ev.split(' ')
1495        report = BeaconReport(binascii.unhexlify(fields[4]))
1496        logger.info("Received beacon report: " + str(report))
1497        if report.bssid_str == apdev[0]['bssid']:
1498            if report.opclass != 81 or report.channel != 1:
1499                raise Exception("Incorrect opclass/channel for AP0")
1500        elif report.bssid_str == apdev[1]['bssid']:
1501            if report.opclass != 81 or report.channel != 11:
1502                raise Exception("Incorrect opclass/channel for AP1")
1503
1504@remote_compatible
1505def test_rrm_beacon_req_active_ignore_old_result(dev, apdev):
1506    """Beacon request - active scan mode and old scan result"""
1507    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another"})
1508    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2412)
1509    hapd2.disable()
1510
1511    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1512    hapd = hostapd.add_ap(apdev[0], params)
1513
1514    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1515    addr = dev[0].own_addr()
1516    hapd.wait_sta()
1517
1518    req = build_beacon_request(chan=1, duration=100, mode=1)
1519    token, resp = run_req_beacon(hapd, addr, req)
1520
1521    if resp:
1522        ev = resp.pop(0)
1523    else:
1524        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1525    if ev is None:
1526        raise Exception("Beacon report response not received")
1527    fields = ev.split(' ')
1528    report = BeaconReport(binascii.unhexlify(fields[4]))
1529    logger.info("Received beacon report: " + str(report))
1530    if report.bssid_str == apdev[1]['bssid']:
1531        raise Exception("Old BSS reported")
1532
1533    if resp:
1534        ev = resp.pop(0)
1535    else:
1536        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1537    if ev is not None:
1538        raise Exception("Unexpected beacon report response")
1539
1540def start_ap(dev):
1541    id = dev.add_network()
1542    dev.set_network(id, "mode", "2")
1543    dev.set_network_quoted(id, "ssid", 32*'A')
1544    dev.set_network_quoted(id, "psk", "1234567890")
1545    dev.set_network(id, "frequency", "2412")
1546    dev.set_network(id, "scan_freq", "2412")
1547    dev.select_network(id)
1548    dev.wait_connected()
1549
1550def test_rrm_beacon_req_active_many(dev, apdev):
1551    """Beacon request - active scan mode and many BSSs"""
1552    for i in range(1, 7):
1553        ifname = apdev[0]['ifname'] if i == 1 else apdev[0]['ifname'] + "-%d" % i
1554        hapd1 = hostapd.add_bss(apdev[0], ifname, 'bss-%i.conf' % i)
1555        hapd1.set('vendor_elements', "dd50" + 80*'bb')
1556        hapd1.request("UPDATE_BEACON")
1557
1558    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1559    wpas.interface_add("wlan5")
1560    wpas.request("SET device_name " + 20*'a')
1561    start_ap(wpas)
1562    start_ap(dev[1])
1563    start_ap(dev[2])
1564
1565    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1566    params['vendor_elements'] = "dd50" + 80*'aa'
1567    hapd = hostapd.add_ap(apdev[1], params)
1568
1569    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1570    addr = dev[0].own_addr()
1571    hapd.wait_sta()
1572
1573    ok = False
1574    for j in range(3):
1575        req = build_beacon_request(chan=1, duration=100, mode=1)
1576        token, resp = run_req_beacon(hapd, addr, req)
1577
1578        for i in range(10):
1579            if resp:
1580                ev = resp.pop(0)
1581            else:
1582                ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1583            if ev is None:
1584                raise Exception("Beacon report %d response not received" % i)
1585            fields = ev.split(' ')
1586            if len(fields[4]) == 0:
1587                break
1588            report = BeaconReport(binascii.unhexlify(fields[4]))
1589            logger.info("Received beacon report: " + str(report))
1590            if i == 9:
1591                ok = True
1592        if ok:
1593            break
1594
1595@remote_compatible
1596def test_rrm_beacon_req_active_ap_channels(dev, apdev):
1597    """Beacon request - active scan mode with AP Channel Report subelement"""
1598    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1599    hapd = hostapd.add_ap(apdev[0], params)
1600    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1601
1602    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1603    addr = dev[0].own_addr()
1604    hapd.wait_sta()
1605
1606    req = build_beacon_request(chan=255, duration=100, mode=1)
1607    token, resp = run_req_beacon(hapd, addr,
1608                                 req + "dd0111" + "330351010b" + "dd0111")
1609
1610    for i in range(1, 3):
1611        if resp:
1612            ev = resp.pop(0)
1613        else:
1614            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1615        if ev is None:
1616            raise Exception("Beacon report %d response not received" % i)
1617        fields = ev.split(' ')
1618        report = BeaconReport(binascii.unhexlify(fields[4]))
1619        logger.info("Received beacon report: " + str(report))
1620        if report.bssid_str == apdev[0]['bssid']:
1621            if report.opclass != 81 or report.channel != 1:
1622                raise Exception("Incorrect opclass/channel for AP0")
1623        elif report.bssid_str == apdev[1]['bssid']:
1624            if report.opclass != 81 or report.channel != 11:
1625                raise Exception("Incorrect opclass/channel for AP1")
1626
1627@remote_compatible
1628def test_rrm_beacon_req_active_no_ir(dev, apdev):
1629    """Beacon request - active scan mode and NO_IR channel"""
1630    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1631    hapd = hostapd.add_ap(apdev[0], params)
1632
1633    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1634    addr = dev[0].own_addr()
1635    hapd.wait_sta()
1636
1637    req = build_beacon_request(opclass=118, chan=52, duration=100, mode=1)
1638    token, resp = run_req_beacon(hapd, addr, req)
1639    if resp:
1640        ev = resp.pop(0)
1641    else:
1642        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1643    if ev is None:
1644        raise Exception("Beacon report response not received")
1645    fields = ev.split(' ')
1646    if fields[2] != token:
1647        raise Exception("Unexpected token value in response (expected %s): %s" % (token, fields[2]))
1648    mode = int(fields[3], base=16)
1649    if mode & 0x04:
1650        raise Exception("Beacon request refused")
1651    report = BeaconReport(binascii.unhexlify(fields[4]))
1652    logger.info("Beacon report: " + str(report))
1653
1654@remote_compatible
1655def test_rrm_beacon_req_passive_ap_channels(dev, apdev):
1656    """Beacon request - passive scan mode with AP Channel Report subelement"""
1657    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1658    hapd = hostapd.add_ap(apdev[0], params)
1659    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1660
1661    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1662    addr = dev[0].own_addr()
1663    hapd.wait_sta()
1664
1665    req = build_beacon_request(chan=255, duration=100)
1666    token, resp = run_req_beacon(hapd, addr,
1667                                 req + "330351010b" + "3300" + "dd00")
1668
1669    for i in range(1, 3):
1670        if resp:
1671            ev = resp.pop(0)
1672        else:
1673            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1674        if ev is None:
1675            raise Exception("Beacon report %d response not received" % i)
1676        fields = ev.split(' ')
1677        report = BeaconReport(binascii.unhexlify(fields[4]))
1678        logger.info("Received beacon report: " + str(report))
1679        if report.bssid_str == apdev[0]['bssid']:
1680            if report.opclass != 81 or report.channel != 1:
1681                raise Exception("Incorrect opclass/channel for AP0")
1682        elif report.bssid_str == apdev[1]['bssid']:
1683            if report.opclass != 81 or report.channel != 11:
1684                raise Exception("Incorrect opclass/channel for AP1")
1685
1686@remote_compatible
1687def test_rrm_beacon_req_active_single_channel(dev, apdev):
1688    """Beacon request - active scan mode with single channel"""
1689    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1690    hapd = hostapd.add_ap(apdev[0], params)
1691    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1692
1693    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1694    addr = dev[0].own_addr()
1695    hapd.wait_sta()
1696
1697    req = build_beacon_request(chan=11, duration=100, mode=1)
1698    token, resp = run_req_beacon(hapd, addr, req)
1699
1700    if resp:
1701        ev = resp.pop(0)
1702    else:
1703        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1704    if ev is None:
1705        raise Exception("Beacon report response not received")
1706    fields = ev.split(' ')
1707    report = BeaconReport(binascii.unhexlify(fields[4]))
1708    logger.info("Received beacon report: " + str(report))
1709
1710@remote_compatible
1711def test_rrm_beacon_req_active_ap_channels_unknown_opclass(dev, apdev):
1712    """Beacon request - active scan mode with AP Channel Report subelement and unknown opclass"""
1713    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1714    hapd = hostapd.add_ap(apdev[0], params)
1715    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1716
1717    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1718    addr = dev[0].own_addr()
1719    hapd.wait_sta()
1720
1721    req = build_beacon_request(chan=255, duration=100, mode=1)
1722    token, resp = run_req_beacon(hapd, addr, req + "3303ff010b")
1723
1724    if resp:
1725        ev = resp.pop(0)
1726    else:
1727        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1728    if ev is None:
1729        raise Exception("Beacon report response (refused) not received")
1730
1731    fields = ev.split(' ')
1732    if fields[3] != "04":
1733        raise Exception("Unexpected beacon report mode: " + fields[3])
1734
1735@remote_compatible
1736def test_rrm_beacon_req_active_ap_channel_oom(dev, apdev):
1737    """Beacon request - AP Channel Report subelement and OOM"""
1738    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1739    hapd = hostapd.add_ap(apdev[0], params)
1740    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1741
1742    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1743    addr = dev[0].own_addr()
1744    hapd.wait_sta()
1745
1746    with alloc_fail(dev[0], 1, "wpas_add_channels"):
1747        req = build_beacon_request(chan=255, duration=100, mode=1)
1748        token, resp = run_req_beacon(hapd, addr, req + "330351010b")
1749        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1750        if resp:
1751            ev = resp.pop(0)
1752        else:
1753            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1754        # allow either not to respond or send refused response
1755        if ev is not None:
1756            fields = ev.split(' ')
1757            if fields[3] != "04":
1758                raise Exception("Unexpected Beacon report during OOM with mode: " + fields[3])
1759
1760@remote_compatible
1761def test_rrm_beacon_req_active_scan_fail(dev, apdev):
1762    """Beacon request - Active scan failure"""
1763    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1764    hapd = hostapd.add_ap(apdev[0], params)
1765
1766    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1767    addr = dev[0].own_addr()
1768    hapd.wait_sta()
1769
1770    with alloc_fail(dev[0], 1,
1771                    "wpa_scan_clone_params;wpa_supplicant_trigger_scan"):
1772        req = build_beacon_request(chan=255, duration=100, mode=1)
1773        token, resp = run_req_beacon(hapd, addr, req + "330351010b")
1774        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1775        if resp:
1776            ev = resp.pop(0)
1777        else:
1778            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1779        if ev is None:
1780            raise Exception("No Beacon report")
1781        fields = ev.split(' ')
1782        if fields[3] != "04":
1783            raise Exception("Unexpected Beacon report contents: " + ev)
1784
1785@remote_compatible
1786def test_rrm_beacon_req_active_zero_duration(dev, apdev):
1787    """Beacon request - Action scan and zero duration"""
1788    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1789    hapd = hostapd.add_ap(apdev[0], params)
1790    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1791
1792    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1793    addr = dev[0].own_addr()
1794    hapd.wait_sta()
1795
1796    req = build_beacon_request(mode=1)
1797    token, resp = run_req_beacon(hapd, addr, req)
1798    if resp:
1799        ev = resp.pop(0)
1800    else:
1801        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1802    if ev is not None:
1803        raise Exception("Unexpected Beacon report")
1804
1805@remote_compatible
1806def test_rrm_beacon_req_active_fail_random(dev, apdev):
1807    """Beacon request - active scan mode os_get_random failure"""
1808    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1809    hapd = hostapd.add_ap(apdev[0], params)
1810    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1811    addr = dev[0].own_addr()
1812    hapd.wait_sta()
1813
1814    with fail_test(dev[0], 1, "os_get_random;wpas_rm_handle_beacon_req"):
1815        req = build_beacon_request(duration=100, mode=1)
1816        token, resp = run_req_beacon(hapd, addr, req)
1817        if resp:
1818            ev = resp.pop(0)
1819        else:
1820            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1821        if ev is None:
1822            raise Exception("Beacon report response not received")
1823        fields = ev.split(' ')
1824        report = BeaconReport(binascii.unhexlify(fields[4]))
1825        logger.info("Received beacon report: " + str(report))
1826
1827@remote_compatible
1828def test_rrm_beacon_req_passive(dev, apdev):
1829    """Beacon request - passive scan mode"""
1830    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1831    hapd = hostapd.add_ap(apdev[0], params)
1832    hapd2 = hostapd.add_ap(apdev[1], {"ssid": "another", "channel": "11"})
1833
1834    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1835    addr = dev[0].own_addr()
1836    hapd.wait_sta()
1837
1838    req = build_beacon_request(duration=100)
1839    token, resp = run_req_beacon(hapd, addr, req)
1840
1841    for i in range(1, 3):
1842        if resp:
1843            ev = resp.pop(0)
1844        else:
1845            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1846        if ev is None:
1847            raise Exception("Beacon report %d response not received" % i)
1848        fields = ev.split(' ')
1849        report = BeaconReport(binascii.unhexlify(fields[4]))
1850        logger.info("Received beacon report: " + str(report))
1851        if report.bssid_str == apdev[0]['bssid']:
1852            if report.opclass != 81 or report.channel != 1:
1853                raise Exception("Incorrect opclass/channel for AP0")
1854        elif report.bssid_str == apdev[1]['bssid']:
1855            if report.opclass != 81 or report.channel != 11:
1856                raise Exception("Incorrect opclass/channel for AP1")
1857
1858@remote_compatible
1859def test_rrm_beacon_req_passive_no_match(dev, apdev):
1860    """Beacon request - passive scan mode and no matching BSS"""
1861    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1862    hapd = hostapd.add_ap(apdev[0], params)
1863
1864    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1865    addr = dev[0].own_addr()
1866    hapd.wait_sta()
1867
1868    req = build_beacon_request(chan=1, duration=100, bssid="02:11:22:33:44:55")
1869    token, resp = run_req_beacon(hapd, addr, req)
1870    if resp:
1871        ev = resp.pop(0)
1872    else:
1873        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1874    if ev is None:
1875        raise Exception("Beacon report %d response not received" % i)
1876    fields = ev.split(' ')
1877    if len(fields[4]) > 0:
1878        raise Exception("Unexpected beacon report BSS")
1879
1880@remote_compatible
1881def test_rrm_beacon_req_passive_no_match_oom(dev, apdev):
1882    """Beacon request - passive scan mode and no matching BSS (OOM)"""
1883    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1884    hapd = hostapd.add_ap(apdev[0], params)
1885
1886    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1887    addr = dev[0].own_addr()
1888    hapd.wait_sta()
1889
1890    req = build_beacon_request(chan=1, duration=100, bssid="02:11:22:33:44:55")
1891    with alloc_fail(dev[0], 1, "wpabuf_resize;wpas_beacon_rep_scan_process"):
1892        token, resp = run_req_beacon(hapd, addr, req)
1893        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1894        if resp:
1895            ev = resp.pop(0)
1896        else:
1897            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
1898        if ev is not None:
1899            raise Exception("Unexpected Beacon report response during OOM")
1900
1901    # verify reporting is still functional
1902    token, resp = run_req_beacon(hapd, addr, req)
1903    if resp:
1904        ev = resp.pop(0)
1905    else:
1906        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1907    if ev is None:
1908        raise Exception("Beacon report %d response not received" % i)
1909    fields = ev.split(' ')
1910    if len(fields[4]) > 0:
1911        raise Exception("Unexpected beacon report BSS")
1912
1913@remote_compatible
1914def test_rrm_beacon_req_active_duration_mandatory(dev, apdev):
1915    """Beacon request - Action scan and duration mandatory"""
1916    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
1917    hapd = hostapd.add_ap(apdev[0], params)
1918
1919    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
1920    addr = dev[0].own_addr()
1921    hapd.wait_sta()
1922
1923    req = build_beacon_request(duration=100, mode=1)
1924    token, resp = run_req_beacon(hapd, addr, "req_mode=10 " + req)
1925    if resp:
1926        ev = resp.pop(0)
1927    else:
1928        ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1929    if ev is None:
1930        raise Exception("No Beacon report response")
1931    fields = ev.split(' ')
1932    rrm = int(dev[0].get_driver_status_field("capa.rrm_flags"), 16)
1933    if rrm & 0x20 == 0x20:
1934        report = BeaconReport(binascii.unhexlify(fields[4]))
1935        logger.info("Received beacon report: " + str(report))
1936    else:
1937        # Driver does not support scan dwell time setting, so wpa_supplicant
1938        # rejects the measurement request due to the mandatory duration using
1939        # Measurement Report Mode field Incapable=1.
1940        if fields[3] != '02':
1941            raise Exception("Unexpected Measurement Report Mode: " + fields[3])
1942        if len(fields[4]) > 0:
1943            raise Exception("Unexpected beacon report received")
1944
1945def test_rrm_beacon_req_passive_scan_vht(dev, apdev):
1946    """Beacon request - passive scan mode - VHT"""
1947    clear_scan_cache(apdev[0])
1948    try:
1949        hapd = None
1950        params = {"ssid": "rrm-vht",
1951                  "country_code": "FI",
1952                  'ieee80211d': '1',
1953                  "hw_mode": "a",
1954                  "channel": "36",
1955                  "ht_capab": "[HT40+]",
1956                  "ieee80211n": "1",
1957                  "ieee80211ac": "1",
1958                  "vht_oper_chwidth": "1",
1959                  "vht_oper_centr_freq_seg0_idx": "42",
1960                  "rrm_beacon_report": "1"}
1961        hapd = hostapd.add_ap(apdev[0], params)
1962
1963        dev[0].scan_for_bss(apdev[0]['bssid'], freq=5180)
1964        dev[0].connect("rrm-vht", key_mgmt="NONE", scan_freq="5180")
1965
1966        addr = dev[0].own_addr()
1967        hapd.wait_sta()
1968
1969        req = build_beacon_request(opclass=128, duration=100)
1970        token, resp = run_req_beacon(hapd, addr, req)
1971        if resp:
1972            ev = resp.pop(0)
1973        else:
1974            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1975        if ev is None:
1976            raise Exception("Beacon report response not received")
1977        fields = ev.split(' ')
1978        report = BeaconReport(binascii.unhexlify(fields[4]))
1979        logger.info("Received beacon report: " + str(report))
1980        if report.opclass != 128 or report.channel != 36:
1981            raise Exception("Incorrect opclass/channel for AP")
1982
1983        req = build_beacon_request(opclass=130, duration=100)
1984        token, resp = run_req_beacon(hapd, addr, req)
1985        if resp:
1986            ev = resp.pop(0)
1987        else:
1988            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
1989        if ev is None:
1990            raise Exception("Beacon report response not received")
1991        fields = ev.split(' ')
1992        report = BeaconReport(binascii.unhexlify(fields[4]))
1993        logger.info("Received beacon report: " + str(report))
1994        if report.opclass != 128 or report.channel != 36:
1995            raise Exception("Incorrect opclass/channel for AP")
1996    except Exception as e:
1997        if isinstance(e, Exception) and str(e) == "AP startup failed":
1998            if not vht_supported():
1999                raise HwsimSkip("80 MHz channel not supported in regulatory information")
2000        raise
2001    finally:
2002        clear_regdom(hapd, dev)
2003
2004def test_rrm_beacon_req_passive_scan_vht160(dev, apdev):
2005    """Beacon request - passive scan mode - VHT160"""
2006    clear_scan_cache(apdev[0])
2007    try:
2008        hapd = None
2009        params = {"ssid": "rrm-vht",
2010                  "country_code": "ZA",
2011                  'ieee80211d': '1',
2012                  "hw_mode": "a",
2013                  "channel": "104",
2014                  "ht_capab": "[HT40-]",
2015                  "vht_capab": "[VHT160]",
2016                  "ieee80211n": "1",
2017                  "ieee80211ac": "1",
2018                  "vht_oper_chwidth": "2",
2019                  "vht_oper_centr_freq_seg0_idx": "114",
2020                  "rrm_beacon_report": "1"}
2021        hapd = hostapd.add_ap(apdev[0], params)
2022
2023        dev[0].scan_for_bss(apdev[0]['bssid'], freq=5520)
2024        dev[0].connect("rrm-vht", key_mgmt="NONE", scan_freq="5520")
2025        sig = dev[0].request("SIGNAL_POLL").splitlines()
2026        if "WIDTH=160 MHz" not in sig:
2027            raise Exception("Unexpected SIGNAL_POLL value: " + str(sig))
2028
2029        addr = dev[0].own_addr()
2030        hapd.wait_sta()
2031
2032        req = build_beacon_request(opclass=129, duration=100)
2033        token, resp = run_req_beacon(hapd, addr, req)
2034        if resp:
2035            ev = resp.pop(0)
2036        else:
2037            ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
2038        if ev is None:
2039            raise Exception("Beacon report response not received")
2040        fields = ev.split(' ')
2041        report = BeaconReport(binascii.unhexlify(fields[4]))
2042        logger.info("Received beacon report: " + str(report))
2043        if report.opclass != 129 or report.channel != 104:
2044            raise Exception("Incorrect opclass/channel for AP")
2045    except Exception as e:
2046        if isinstance(e, Exception) and str(e) == "AP startup failed":
2047            raise HwsimSkip("ZA regulatory rule likely did not have DFS requirement removed")
2048        raise
2049    finally:
2050        clear_regdom(hapd, dev)
2051
2052def test_rrm_beacon_req_ap_errors(dev, apdev):
2053    """Beacon request - AP error cases"""
2054    try:
2055        run_rrm_beacon_req_ap_errors(dev, apdev)
2056    finally:
2057        dev[1].request("VENDOR_ELEM_REMOVE 13 *")
2058
2059def run_rrm_beacon_req_ap_errors(dev, apdev):
2060    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
2061    hapd = hostapd.add_ap(apdev[0], params)
2062    bssid = hapd.own_addr()
2063    dev[0].scan_for_bss(bssid, freq=2412)
2064    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2065    addr = dev[0].own_addr()
2066    # Override RM capabilities (remove all)
2067    dev[1].request("VENDOR_ELEM_ADD 13 46050000000000")
2068    dev[1].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2069    addr1 = dev[1].own_addr()
2070
2071    # Beacon request: Too short request data
2072    if "FAIL" not in hapd.request("REQ_BEACON " + addr + " 11"):
2073        raise Exception("Invalid REQ_BEACON accepted")
2074
2075    # Beacon request: 02:00:00:00:01:00 does not support table beacon report
2076    req = build_beacon_request(mode=2)
2077    if "FAIL" not in hapd.request("REQ_BEACON " + addr1 + " " + req):
2078        raise Exception("Invalid REQ_BEACON accepted")
2079
2080    # Beacon request: 02:00:00:00:01:00 does not support active beacon report
2081    if "FAIL" not in hapd.request("REQ_BEACON " + addr1 + " 51000000640001ffffffffffff"):
2082        raise Exception("Invalid REQ_BEACON accepted")
2083
2084    # Beacon request: 02:00:00:00:01:00 does not support passive beacon report
2085    if "FAIL" not in hapd.request("REQ_BEACON " + addr1 + " 510b0000640000ffffffffffff"):
2086        raise Exception("Invalid REQ_BEACON accepted")
2087
2088    # Beacon request: Unknown measurement mode 3
2089    if "FAIL" not in hapd.request("REQ_BEACON " + addr1 + " 510b0000640003ffffffffffff"):
2090        raise Exception("Invalid REQ_BEACON accepted")
2091
2092    for i in range(257):
2093        if "FAIL" in hapd.request("REQ_BEACON " + addr + " 510b0000640000ffffffffffff"):
2094            raise Exception("REQ_BEACON failed")
2095        dev[0].dump_monitor()
2096        hapd.dump_monitor()
2097
2098    with alloc_fail(hapd, 1, "wpabuf_alloc;hostapd_send_beacon_req"):
2099        if "FAIL" not in hapd.request("REQ_BEACON " + addr + " 510b0000640000ffffffffffff"):
2100            raise Exception("REQ_BEACON accepted during OOM")
2101
2102    with fail_test(hapd, 1, "nl80211_send_frame_cmd;hostapd_send_beacon_req"):
2103        if "FAIL" not in hapd.request("REQ_BEACON " + addr + " 510b0000640000ffffffffffff"):
2104            raise Exception("REQ_BEACON accepted during failure testing")
2105
2106def test_rrm_req_reject_oom(dev, apdev):
2107    """Radio measurement request - OOM while rejecting a request"""
2108    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
2109    hapd = hostapd.add_ap(apdev[0], params)
2110    bssid = hapd.own_addr()
2111
2112    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2113    addr = dev[0].own_addr()
2114
2115    hdr = "d0003a01" + addr.replace(':', '') + 2*bssid.replace(':', '') + "1000"
2116
2117    hapd.set("ext_mgmt_frame_handling", "1")
2118    dev[0].request("SET ext_mgmt_frame_handling 1")
2119
2120    with alloc_fail(dev[0], 1, "wpabuf_resize;wpas_rrm_handle_msr_req_element"):
2121        # "RRM: Parallel measurements are not supported, reject"
2122        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "05000100002603010105"):
2123            raise Exception("MGMT_RX_PROCESS failed")
2124        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
2125        ev = hapd.wait_event(["MGMT-RX"], timeout=0.2)
2126        if ev is not None:
2127            raise Exception("Unexpected beacon report response during OOM")
2128
2129def test_rrm_req_when_rrm_not_used(dev, apdev):
2130    """Radio/link measurement request for non-RRM association"""
2131    params = {"ssid": "rrm"}
2132    hapd = hostapd.add_ap(apdev[0], params)
2133    bssid = hapd.own_addr()
2134
2135    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2136    addr = dev[0].own_addr()
2137
2138    hdr = "d0003a01" + addr.replace(':', '') + 2*bssid.replace(':', '') + "1000"
2139
2140    hapd.set("ext_mgmt_frame_handling", "1")
2141    dev[0].request("SET ext_mgmt_frame_handling 1")
2142
2143    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "050001000026030100fe"):
2144        raise Exception("MGMT_RX_PROCESS failed")
2145    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "0502000000"):
2146        raise Exception("MGMT_RX_PROCESS failed")
2147    ev = hapd.wait_event(["MGMT-RX"], timeout=0.2)
2148    if ev is not None:
2149        raise Exception("Unexpected beacon report response when RRM is disabled")
2150
2151    dev[0].request("REMOVE_NETWORK all")
2152    dev[0].wait_disconnected()
2153    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "050001000026030100fe"):
2154        raise Exception("MGMT_RX_PROCESS failed")
2155    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "0502000000"):
2156        raise Exception("MGMT_RX_PROCESS failed")
2157
2158@remote_compatible
2159def test_rrm_req_proto(dev, apdev):
2160    """Radio measurement request - protocol testing"""
2161    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
2162    hapd = hostapd.add_ap(apdev[0], params)
2163    bssid = hapd.own_addr()
2164
2165    dev[0].request("SET LCI ")
2166    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2167    addr = dev[0].own_addr()
2168
2169    hdr = "d0003a01" + addr.replace(':', '') + 2*bssid.replace(':', '') + "1000"
2170
2171    hapd.set("ext_mgmt_frame_handling", "1")
2172    dev[0].request("SET ext_mgmt_frame_handling 1")
2173
2174    tests = []
2175    # "RRM: Ignoring too short radio measurement request"
2176    tests += ["0500", "050001", "05000100"]
2177    # No measurement request element at all
2178    tests += ["0500010000"]
2179    # "RRM: Truncated element"
2180    tests += ["050001000026"]
2181    # "RRM: Element length too short"
2182    tests += ["05000100002600", "0500010000260111", "050001000026021122"]
2183    # "RRM: Element length too long"
2184    tests += ["05000100002603", "0500010000260311", "050001000026031122"]
2185    # "RRM: Enable bit not supported, ignore"
2186    tests += ["05000100002603010200"]
2187    # "RRM: Measurement report failed. TX power insertion not supported"
2188    #    OR
2189    # "RRM: Link measurement report failed. Request too short"
2190    tests += ["0502"]
2191    # Too short LCI request
2192    tests += ["05000100002603010008"]
2193    # Too short neighbor report response
2194    tests += ["0505"]
2195    # Unexpected neighbor report response
2196    tests += ["050500", "050501", "050502", "050503", "050504", "050505"]
2197    # Too short beacon request
2198    tests += ["05000100002603010005",
2199              "0500010000260f010005112233445566778899aabbcc"]
2200    # Unknown beacon report mode
2201    tests += ["05000100002610010005112233445566778899aabbccdd"]
2202    # "RRM: Expected Measurement Request element, but EID is 0"
2203    tests += ["05000100000000"]
2204    for t in tests:
2205        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2206            raise Exception("MGMT_RX_PROCESS failed")
2207    ev = hapd.wait_event(["MGMT-RX"], timeout=0.2)
2208    if ev is not None:
2209        raise Exception("Unexpected response seen at the AP: " + ev)
2210
2211    tests = []
2212    # "RRM: Parallel measurements are not supported, reject"
2213    tests += ["05000100002603010105"]
2214    # "RRM: Unsupported radio measurement type 254"
2215    tests += ["050001000026030100fe"]
2216    # Reject LCI request
2217    tests += ["0500010000260701000811223344"]
2218    # Beacon report info subelement; no valid channels
2219    tests += ["05000100002614010005112233445566008899aabbccdd01020000"]
2220    for t in tests:
2221        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2222            raise Exception("MGMT_RX_PROCESS failed")
2223        ev = hapd.wait_event(["MGMT-RX"], timeout=5)
2224        if ev is None:
2225            raise Exception("No response seen at the AP")
2226        hapd.dump_monitor()
2227
2228    dev[0].request("SET LCI " + lci)
2229    tests = []
2230    # "Not building LCI report - bad location subject"
2231    tests += ["0500010000260701000811223344"]
2232    for t in tests:
2233        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2234            raise Exception("MGMT_RX_PROCESS failed")
2235    ev = hapd.wait_event(["MGMT-RX"], timeout=0.2)
2236    if ev is not None:
2237        raise Exception("Unexpected response seen at the AP: " + ev)
2238
2239    tests = []
2240    # LCI report or reject
2241    tests += ["0500010000260701000801223344",
2242              "05000100002607010008010402ff",
2243              "05000100002608010008010402ffff"]
2244    for t in tests:
2245        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2246            raise Exception("MGMT_RX_PROCESS failed")
2247        ev = hapd.wait_event(["MGMT-RX"], timeout=5)
2248        if ev is None:
2249            raise Exception("No response seen at the AP")
2250        hapd.dump_monitor()
2251
2252    # Verify rejection of a group-addressed request frame
2253    hdr = "d0003a01" + "ffffffffffff" + 2*bssid.replace(':', '') + "1000"
2254    # "RRM: Parallel measurements are not supported, reject"
2255    t = "05000100002603010105"
2256    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2257        raise Exception("MGMT_RX_PROCESS failed")
2258    ev = hapd.wait_event(["MGMT-RX"], timeout=0.1)
2259    if ev is not None:
2260        raise Exception("Unexpected response seen at the AP (broadcast request rejected)")
2261    hapd.dump_monitor()
2262
2263    hapd.set("ext_mgmt_frame_handling", "0")
2264    dev[0].request("SET ext_mgmt_frame_handling 0")
2265    dev[0].request("SET LCI ")
2266
2267def test_rrm_link_measurement(dev, apdev):
2268    """Radio measurement request - link measurement"""
2269    check_tx_power_support(dev[0])
2270    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
2271    hapd = hostapd.add_ap(apdev[0], params)
2272    bssid = hapd.own_addr()
2273
2274    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2275    addr = dev[0].own_addr()
2276
2277    hdr = "d0003a01" + addr.replace(':', '') + 2*bssid.replace(':', '') + "1000"
2278
2279    hapd.set("ext_mgmt_frame_handling", "1")
2280    dev[0].request("SET ext_mgmt_frame_handling 1")
2281
2282    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "0502000000"):
2283        raise Exception("MGMT_RX_PROCESS failed")
2284    ev = hapd.wait_event(["MGMT-RX"], timeout=5)
2285    if ev is None:
2286        raise Exception("No link measurement report seen")
2287
2288def test_rrm_link_measurement_oom(dev, apdev):
2289    """Radio measurement request - link measurement OOM"""
2290    check_tx_power_support(dev[0])
2291    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
2292    hapd = hostapd.add_ap(apdev[0], params)
2293    bssid = hapd.own_addr()
2294
2295    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2296    addr = dev[0].own_addr()
2297
2298    hdr = "d0003a01" + addr.replace(':', '') + 2*bssid.replace(':', '') + "1000"
2299
2300    hapd.set("ext_mgmt_frame_handling", "1")
2301    dev[0].request("SET ext_mgmt_frame_handling 1")
2302
2303    with alloc_fail(dev[0], 1, "wpabuf_alloc;wpas_rrm_handle_link_measurement_request"):
2304        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "0502000000"):
2305            raise Exception("MGMT_RX_PROCESS failed")
2306        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
2307
2308    with fail_test(dev[0], 1, "wpas_rrm_handle_link_measurement_request"):
2309        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "0502000000"):
2310            raise Exception("MGMT_RX_PROCESS failed")
2311        wait_fail_trigger(dev[0], "GET_FAIL")
2312
2313    ev = hapd.wait_event(["MGMT-RX"], timeout=0.1)
2314    if ev is not None:
2315        raise Exception("Unexpected beacon report response during OOM")
2316
2317def test_rrm_rep_parse_proto(dev, apdev):
2318    """hostapd rrm report parsing protocol testing"""
2319    check_rrm_support(dev[0])
2320
2321    params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
2322    hapd = hostapd.add_ap(apdev[0], params)
2323    bssid = hapd.own_addr()
2324
2325    dev[0].request("SET LCI " + lci)
2326    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2327    addr = dev[0].own_addr()
2328
2329    hdr = "d0003a01" + bssid.replace(':', '') + addr.replace(':', '') + bssid.replace(':', '') + "1000"
2330    hapd.set("ext_mgmt_frame_handling", "1")
2331
2332    tests = ["0501",
2333             "05ff01",
2334             "0501012703fffffe2700",
2335             "0501012703ffff05",
2336             "05010127ffffff05" + 252*"00",
2337             "0504012603ffffff2600",
2338             "0504012603ffff08",
2339             "0504012608ffff08ffffffffff",
2340             "0504012608ffff08ff04021234",
2341             "0504012608ffff08ff04020100",
2342             "0504012608ffff08ff0402ffff"]
2343    for t in tests:
2344        if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2345            raise Exception("MGMT_RX_PROCESS failed for " + t)
2346
2347    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"rrm\" nr=" + nr + " lci=" + lci):
2348        raise Exception("Set neighbor failed")
2349    if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "0504012608ffff08ff04021000"):
2350        raise Exception("MGMT_RX_PROCESS failed")
2351
2352def test_rrm_unexpected(dev, apdev):
2353    """hostapd unexpected rrm"""
2354    check_rrm_support(dev[0])
2355
2356    params = {"ssid": "rrm", "rrm_neighbor_report": "0"}
2357    hapd = hostapd.add_ap(apdev[0], params)
2358    bssid = hapd.own_addr()
2359
2360    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2361    addr = dev[0].own_addr()
2362
2363    hdr = "d0003a01" + bssid.replace(':', '') + addr.replace(':', '') + bssid.replace(':', '') + "1000"
2364    hapd.set("ext_mgmt_frame_handling", "1")
2365
2366    tests = ["050401"]
2367    for t in tests:
2368        if "OK" not in hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + t):
2369            raise Exception("MGMT_RX_PROCESS failed for " + t)
2370
2371def check_beacon_req(hapd, addr, idx):
2372    req = build_beacon_request(mode=2)
2373    request = req + "020100"
2374    token = hapd.request("REQ_BEACON " + addr + " " + request)
2375    if "FAIL" in token:
2376        raise Exception("REQ_BEACON failed (%d)" % idx)
2377    ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
2378    if ev is None:
2379        raise Exception("Beacon report response not received (%d)" % idx)
2380
2381def test_rrm_reassociation(dev, apdev):
2382    """Radio measurement request - reassociation"""
2383    params = {"ssid": "rrm", "rrm_beacon_report": "1"}
2384    hapd = hostapd.add_ap(apdev[0], params)
2385    bssid = hapd.own_addr()
2386
2387    addr = dev[0].own_addr()
2388    dev[0].flush_scan_cache()
2389    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
2390    hapd.wait_sta()
2391    check_beacon_req(hapd, addr, 1)
2392
2393    dev[0].request("REASSOCIATE")
2394    dev[0].wait_connected()
2395    hapd.wait_sta()
2396    check_beacon_req(hapd, addr, 1)
2397
2398    hapd2 = hostapd.add_ap(apdev[1], params)
2399    bssid2 = hapd2.own_addr()
2400    dev[0].scan_for_bss(bssid2, freq=2412, force_scan=True)
2401    dev[0].roam(bssid2)
2402    hapd2.wait_sta()
2403    check_beacon_req(hapd2, addr, 2)
2404
2405    dev[0].scan_for_bss(bssid, freq=2412)
2406    dev[0].roam(bssid)
2407    hapd.wait_sta()
2408    check_beacon_req(hapd, addr, 3)
2409