tests: Beacon request - beacon table mode

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2017-01-02 00:42:25 +02:00
parent ec45927b8a
commit 42b0982376

View file

@ -1,16 +1,21 @@
# Radio measurement
# Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
# Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
# Copyright (c) 2017, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import binascii
import re
import logging
logger = logging.getLogger()
import struct
import subprocess
import hostapd
from utils import HwsimSkip
from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
from test_ap_ht import clear_scan_cache
nr="00112233445500000000510107"
lci="01000800101298c0b512926666f6c2f1001c00004104050000c00012"
@ -376,3 +381,442 @@ def _test_rrm_ftm_capa_indication(dev, apdev):
if "OK" not in dev[0].request("SET ftm_responder 1"):
raise Exception("could not set ftm_responder")
dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412, force_scan=True)
class BeaconReport:
def __init__(self, report):
self.opclass, self.channel, self.start, self.duration, self.frame_info, self.rcpi, self.rsni = struct.unpack("<BBQHBBB", report[0:15])
report = report[15:]
self.bssid = report[0:6]
self.bssid_str = "%02x:%02x:%02x:%02x:%02x:%02x" % (struct.unpack('6B', self.bssid))
report = report[6:]
self.antenna_id, self.parent_tsf = struct.unpack("<BI", report[0:5])
report = report[5:]
self.subelems = report
self.frame_body = None
while len(report) >= 2:
eid,elen = struct.unpack('BB', report[0:2])
report = report[2:]
if len(report) < elen:
raise Exception("Invalid subelement in beacon report")
if eid == 1:
# Reported Frame Body
# Contents depends on the reporting detail request:
# 0 = no Reported Frame Body subelement
# 1 = all fixed fields and any elements identified in Request
# element
# 2 = all fixed fields and all elements
# Fixed fields: Timestamp[8] BeaconInt[2] CapabInfo[2]
self.frame_body = report[0:elen]
report = report[elen:]
def __str__(self):
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)
if self.frame_body:
txt += " frame_body=" + binascii.hexlify(self.frame_body)
return txt
def run_req_beacon(hapd, addr, request):
token = hapd.request("REQ_BEACON " + addr + " " + request)
if "FAIL" in token:
raise Exception("REQ_BEACON failed")
ev = hapd.wait_event(["BEACON-REQ-TX-STATUS"], timeout=5)
if ev is None:
raise Exception("No TX status event for beacon request received")
fields = ev.split(' ')
if fields[1] != addr:
raise Exception("Unexpected STA address in TX status: " + fields[1])
if fields[2] != token:
raise Exception("Unexpected dialog token in TX status: " + fields[2] + " (expected " + token + ")")
if fields[3] != "ack=1":
raise Exception("Unexected ACK status in TX status: " + fields[3])
return token
def test_rrm_beacon_req_table(dev, apdev):
"""Beacon request - beacon table mode"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "another" })
tests = [ "REQ_BEACON ",
"REQ_BEACON q",
"REQ_BEACON 11:22:33:44:55:66 1",
"REQ_BEACON 11:22:33:44:55:66 1q",
"REQ_BEACON 11:22:33:44:55:66 11223344556677889900aabbccddeeff" ]
for t in tests:
if "FAIL" not in hapd.request(t):
raise Exception("Invalid command accepted: " + t)
dev[0].scan_for_bss(apdev[1]['bssid'], freq=2412)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff")
for i in range(1, 3):
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report %d response not received" % i)
fields = ev.split(' ')
if fields[1] != addr:
raise Exception("Unexpected STA address in beacon report response: " + fields[1])
if fields[2] != token:
raise Exception("Unexpected dialog token in beacon report response: " + fields[2] + " (expected " + token + ")")
if fields[3] != "00":
raise Exception("Unexpected measurement report mode")
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
# Default reporting detail is 2, i.e., all fixed fields and elements.
if not report.frame_body:
raise Exception("Reported Frame Body subelement missing")
if len(report.frame_body) <= 12:
raise Exception("Too short Reported Frame Body subelement")
def test_rrm_beacon_req_table_detail(dev, apdev):
"""Beacon request - beacon table mode - reporting detail"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
logger.info("Reporting Detail 0")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020100")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if report.frame_body:
raise Exception("Reported Frame Body subelement included with Reporting Detail 0")
hapd.dump_monitor()
logger.info("Reporting Detail 1")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if not report.frame_body:
raise Exception("Reported Frame Body subelement missing")
if len(report.frame_body) != 12:
raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 1")
hapd.dump_monitor()
logger.info("Reporting Detail 2")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020102")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if not report.frame_body:
raise Exception("Reported Frame Body subelement missing")
if len(report.frame_body) <= 12:
raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 2")
hapd.dump_monitor()
logger.info("Reporting Detail 3 (invalid)")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020103")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response to invalid reporting detail 3")
hapd.dump_monitor()
logger.info("Reporting Detail (too short)")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "0200")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response to invalid reporting detail")
hapd.dump_monitor()
def test_rrm_beacon_req_table_request(dev, apdev):
"""Beacon request - beacon table mode - request element"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a03000106")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if not report.frame_body:
raise Exception("Reported Frame Body subelement missing")
if len(report.frame_body) != 12 + 5 + 10:
raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 1 and requested elements SSID + SuppRates")
hapd.dump_monitor()
logger.info("Incorrect reporting detail with request subelement")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020102" + "0a03000106")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (invalid reporting detail)")
hapd.dump_monitor()
logger.info("Invalid request subelement length")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a00")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (invalid request subelement length)")
hapd.dump_monitor()
logger.info("Multiple request subelements")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a0100" + "0a0101")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (multiple request subelements)")
hapd.dump_monitor()
def test_rrm_beacon_req_table_request_oom(dev, apdev):
"""Beacon request - beacon table mode - request element OOM"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
with alloc_fail(dev[0], 1,
"bitfield_alloc;wpas_rm_handle_beacon_req_subelem"):
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a03000106")
wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
if ev is not None:
raise Exception("Unexpected beacon report response received (OOM)")
with alloc_fail(dev[0], 1,
"wpabuf_alloc;wpas_rrm_send_msr_report_mpdu"):
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a03000106")
wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
if ev is not None:
raise Exception("Unexpected beacon report response received (OOM)")
with fail_test(dev[0], 1,
"wpa_driver_nl80211_send_action;wpas_rrm_send_msr_report_mpdu"):
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a03000106")
wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
if ev is not None:
raise Exception("Unexpected beacon report response received (OOM)")
with alloc_fail(dev[0], 1,
"wpabuf_resize;wpas_add_beacon_rep"):
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a03000106")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received (OOM -> empty report)")
fields = ev.split(' ')
if len(fields[4]) > 0:
raise Exception("Unexpected beacon report received")
def test_rrm_beacon_req_table_bssid(dev, apdev):
"""Beacon request - beacon table mode - specific BSSID"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "another" })
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
bssid2 = hapd2.own_addr()
token = run_req_beacon(hapd, addr, "51000000000002" + bssid2.replace(':', ''))
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if "bssid=" + bssid2 not in str(report):
raise Exception("Report for unexpect BSS")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
if ev is not None:
raise Exception("Unexpected beacon report response")
def test_rrm_beacon_req_table_ssid(dev, apdev):
"""Beacon request - beacon table mode - specific SSID"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "another" })
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
bssid2 = hapd2.own_addr()
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "0007" + "another".encode('hex'))
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if "bssid=" + bssid2 not in str(report):
raise Exception("Report for unexpect BSS")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.1)
if ev is not None:
raise Exception("Unexpected beacon report response")
hapd.dump_monitor()
logger.info("Wildcard SSID")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "0000")
for i in range(2):
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
hapd.dump_monitor()
logger.info("Too long SSID")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "0021" + 33*"00")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (invalid SSID subelement in request)")
hapd.dump_monitor()
def test_rrm_beacon_req_table_info(dev, apdev):
"""Beacon request - beacon table mode - Reporting Information subelement"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
logger.info("Unsupported reporting information 1")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "01020100")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (unsupported reporting information 1)")
hapd.dump_monitor()
logger.info("Invalid reporting information length")
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "010100")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (invalid reporting information length)")
hapd.dump_monitor()
def test_rrm_beacon_req_table_unknown_subelem(dev, apdev):
"""Beacon request - beacon table mode - unknown subelement"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "330101" + "fe00")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
def test_rrm_beacon_req_table_truncated_subelem(dev, apdev):
"""Beacon request - beacon table mode - Truncated subelement"""
params = { "ssid": "rrm", "rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "0001")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=0.2)
if ev is not None:
raise Exception("Unexpected beacon report response (truncated subelement)")
hapd.dump_monitor()
def test_rrm_beacon_req_table_rsne(dev, apdev):
"""Beacon request - beacon table mode - RSNE truncation"""
params = hostapd.wpa2_params(ssid="rrm-rsn", passphrase="12345678")
params["rrm_beacon_report"] = "1"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
dev[0].connect("rrm-rsn", psk="12345678", scan_freq="2412")
addr = dev[0].own_addr()
token = run_req_beacon(hapd, addr, "51000000000002ffffffffffff" + "020101" + "0a0130")
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report response not received")
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if not report.frame_body:
raise Exception("Reported Frame Body subelement missing")
if len(report.frame_body) != 12 + 6:
raise Exception("Unexpected Reported Frame Body subelement length with Reporting Detail 1 and requested element RSNE")
if binascii.unhexlify("30040100000f") not in report.frame_body:
raise Exception("Truncated RSNE not found")
def test_rrm_beacon_req_table_vht(dev, apdev):
"""Beacon request - beacon table mode - VHT"""
clear_scan_cache(apdev[0])
try:
hapd = None
params = { "ssid": "rrm-vht",
"country_code": "FI",
"hw_mode": "a",
"channel": "36",
"ht_capab": "[HT40+]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "1",
"vht_oper_centr_freq_seg0_idx": "42",
"rrm_beacon_report": "1" }
hapd = hostapd.add_ap(apdev[0], params)
bssid = apdev[0]['bssid']
params = { "ssid": "test-vht40",
"country_code": "FI",
"hw_mode": "a",
"channel": "48",
"ieee80211n": "1",
"ieee80211ac": "1",
"ht_capab": "[HT40-]",
"vht_capab": "",
"vht_oper_chwidth": "0",
"vht_oper_centr_freq_seg0_idx": "0",
}
hapd2 = hostapd.add_ap(apdev[1], params)
dev[0].scan_for_bss(apdev[1]['bssid'], freq=5240)
dev[0].connect("rrm-vht", key_mgmt="NONE", scan_freq="5180")
addr = dev[0].own_addr()
token = run_req_beacon(hapd, addr, "f0000000000002ffffffffffff")
for i in range(2):
ev = hapd.wait_event(["BEACON-RESP-RX"], timeout=10)
if ev is None:
raise Exception("Beacon report %d response not received" % i)
fields = ev.split(' ')
report = BeaconReport(binascii.unhexlify(fields[4]))
logger.info("Received beacon report: " + str(report))
if report.bssid_str == apdev[0]['bssid']:
if report.opclass != 128 or report.channel != 36:
raise Exception("Incorrect opclass/channel for AP0")
elif report.bssid_str == apdev[1]['bssid']:
if report.opclass != 117 or report.channel != 48:
raise Exception("Incorrect opclass/channel for AP1")
except Exception, e:
if isinstance(e, Exception) and str(e) == "AP startup failed":
if not vht_supported():
raise HwsimSkip("80 MHz channel not supported in regulatory information")
raise
finally:
dev[0].request("DISCONNECT")
if hapd:
hapd.request("DISABLE")
subprocess.call(['iw', 'reg', 'set', '00'])
dev[0].flush_scan_cache()