hostapd/tests/hwsim/test_cfg80211.py
Jouni Malinen 91b9786ced tests: cfg80211_tx_frame: filter frames based on SA
This makes the test care less likely to fail due to another STA
happening to be listening for Public Action frames and replying to the
P2P GO Negotiation Request.

Signed-off-by: Jouni Malinen <j@w1.fi>
2024-03-17 19:55:11 +02:00

152 lines
6.6 KiB
Python

# cfg80211 test cases
# Copyright (c) 2014, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
from remotehost import remote_compatible
import logging
logger = logging.getLogger()
import binascii
import os
import time
import hostapd
import hwsim_utils
from tshark import run_tshark
from nl80211 import *
from wpasupplicant import WpaSupplicant
from utils import *
def nl80211_command(dev, cmd, attr):
res = dev.request("VENDOR ffffffff {} {}".format(nl80211_cmd[cmd],
binascii.hexlify(attr).decode()))
if "FAIL" in res:
raise Exception("nl80211 command failed")
return binascii.unhexlify(res)
@remote_compatible
def test_cfg80211_disassociate(dev, apdev):
"""cfg80211 disassociation command"""
hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
if ev is None:
raise Exception("No connection event received from hostapd")
ifindex = int(dev[0].get_driver_status_field("ifindex"))
attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
attrs += build_nl80211_attr_u16('REASON_CODE', 1)
attrs += build_nl80211_attr_mac('MAC', apdev[0]['bssid'])
nl80211_command(dev[0], 'DISASSOCIATE', attrs)
ev = hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=5)
if ev is None:
raise Exception("No disconnection event received from hostapd")
def nl80211_frame(dev, ifindex, frame, freq=None, duration=None, offchannel_tx_ok=False):
attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
if freq is not None:
attrs += build_nl80211_attr_u32('WIPHY_FREQ', freq)
if duration is not None:
attrs += build_nl80211_attr_u32('DURATION', duration)
if offchannel_tx_ok:
attrs += build_nl80211_attr_flag('OFFCHANNEL_TX_OK')
attrs += build_nl80211_attr('FRAME', frame)
return parse_nl80211_attrs(nl80211_command(dev, 'FRAME', attrs))
def nl80211_frame_wait_cancel(dev, ifindex, cookie):
attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
attrs += build_nl80211_attr('COOKIE', cookie)
return nl80211_command(dev, 'FRAME_WAIT_CANCEL', attrs)
def nl80211_remain_on_channel(dev, ifindex, freq, duration):
attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
attrs += build_nl80211_attr_u32('WIPHY_FREQ', freq)
attrs += build_nl80211_attr_u32('DURATION', duration)
return nl80211_command(dev, 'REMAIN_ON_CHANNEL', attrs)
def test_cfg80211_tx_frame(dev, apdev, params):
"""cfg80211 offchannel TX frame command"""
dev[0].p2p_start_go(freq='2412')
go = WpaSupplicant(dev[0].group_ifname)
addr = go.own_addr()
frame = binascii.unhexlify("d0000000020000000100" + addr.replace(':', '') + "02000000010000000409506f9a090001dd5e506f9a0902020025080401001f0502006414060500585804510b0906000200000000000b1000585804510b0102030405060708090a0b0d1d000200000000000108000000000000000000101100084465766963652041110500585804510bdd190050f204104a0001101012000200011049000600372a000120")
ifindex = int(go.get_driver_status_field("ifindex"))
res = nl80211_frame(go, ifindex, frame, freq=2422, duration=500,
offchannel_tx_ok=True)
time.sleep(0.1)
# note: Uncommenting this seems to remove the incorrect channel issue
#nl80211_frame_wait_cancel(dev[0], ifindex, res[nl80211_attr['COOKIE']])
# note: this Action frame ends up getting sent incorrectly on 2422 MHz
nl80211_frame(go, ifindex, frame, freq=2412)
time.sleep(1.5)
# note: also the Deauthenticate frame sent by the GO going down ends up
# being transmitted incorrectly on 2422 MHz.
del go
out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
"wlan.fc.type_subtype == 13 && wlan.sa == " + addr,
["radiotap.channel.freq"])
if out is not None:
freq = out.splitlines()
if len(freq) != 2:
raise Exception("Unexpected number of Action frames (%d)" % len(freq))
if freq[0] != "2422":
raise Exception("First Action frame on unexpected channel: %s MHz" % freq[0])
if freq[1] != "2412":
raise Exception("Second Action frame on unexpected channel: %s MHz" % freq[1])
@remote_compatible
def test_cfg80211_wep_key_idx_change(dev, apdev):
"""WEP Shared Key authentication and key index change without deauth"""
check_wep_capa(dev[0])
hapd = hostapd.add_ap(apdev[0],
{"ssid": "wep-shared-key",
"wep_key0": '"hello12345678"',
"wep_key1": '"other12345678"',
"auth_algs": "2"})
id = dev[0].connect("wep-shared-key", key_mgmt="NONE", auth_alg="SHARED",
wep_key0='"hello12345678"',
wep_key1='"other12345678"',
wep_tx_keyidx="0",
scan_freq="2412")
hwsim_utils.test_connectivity(dev[0], hapd)
dev[0].set_network(id, "wep_tx_keyidx", "1")
# clear cfg80211 auth state to allow new auth without deauth frame
ifindex = int(dev[0].get_driver_status_field("ifindex"))
attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
attrs += build_nl80211_attr_u16('REASON_CODE', 1)
attrs += build_nl80211_attr_mac('MAC', apdev[0]['bssid'])
attrs += build_nl80211_attr_flag('LOCAL_STATE_CHANGE')
nl80211_command(dev[0], 'DEAUTHENTICATE', attrs)
dev[0].wait_disconnected(timeout=5, error="Local-deauth timed out")
# the previous command results in deauth event followed by auto-reconnect
dev[0].wait_connected(timeout=10, error="Reassociation timed out")
hwsim_utils.test_connectivity(dev[0], hapd)
@remote_compatible
def test_cfg80211_hostapd_ext_sta_remove(dev, apdev):
"""cfg80211 DEL_STATION issued externally to hostapd"""
hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
id = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
ifindex = int(hapd.get_driver_status_field("ifindex"))
attrs = build_nl80211_attr_u32('IFINDEX', ifindex)
attrs += build_nl80211_attr_u16('REASON_CODE', 1)
attrs += build_nl80211_attr_u8('MGMT_SUBTYPE', 12)
attrs += build_nl80211_attr_mac('MAC', dev[0].own_addr())
nl80211_command(hapd, 'DEL_STATION', attrs)
# Currently, hostapd ignores the NL80211_CMD_DEL_STATION event if
# drv->device_ap_sme == 0 (which is the case with mac80211_hwsim), so no
# further action happens here. If that event were to be used to remove the
# STA entry from hostapd even in device_ap_sme == 0 case, this test case
# could be extended to cover additional operations.