1# Test a few kernel bugs and functionality
2# Copyright (c) 2016, Intel Deutschland GmbH
3#
4# Author: Johannes Berg <johannes.berg@intel.com>
5#
6# This software may be distributed under the terms of the BSD license.
7# See README for more details.
8
9import hostapd
10import binascii
11import os
12import struct
13from test_wnm import expect_ack
14from tshark import run_tshark
15
16def _test_kernel_bss_leak(dev, apdev, deauth):
17    ssid = "test-bss-leak"
18    passphrase = 'qwertyuiop'
19    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
20    hapd = hostapd.add_ap(apdev[0], params)
21    hapd.set("ext_mgmt_frame_handling", "1")
22    dev[0].connect(ssid, psk=passphrase, scan_freq="2412", wait_connect=False)
23    while True:
24        pkt = hapd.mgmt_rx()
25        if not pkt:
26            raise Exception("MGMT RX wait timed out for auth frame")
27        if pkt['fc'] & 0xc:
28            continue
29        if pkt['subtype'] == 0: # assoc request
30            if deauth:
31                # return a deauth immediately
32                hapd.mgmt_tx({
33                    'fc': 0xc0,
34                    'sa': pkt['da'],
35                    'da': pkt['sa'],
36                    'bssid': pkt['bssid'],
37                    'payload': b'\x01\x00',
38                })
39            break
40        else:
41            hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % (
42                         binascii.hexlify(pkt['frame']).decode(), ))
43    hapd.set("ext_mgmt_frame_handling", "0")
44
45    hapd.request("STOP_AP")
46
47    dev[0].request("REMOVE_NETWORK all")
48    dev[0].wait_disconnected()
49
50    dev[0].flush_scan_cache(freq=5180)
51    res = dev[0].request("SCAN_RESULTS")
52    if len(res.splitlines()) > 1:
53        raise Exception("BSS entry should no longer be around")
54
55def test_kernel_bss_leak_deauth(dev, apdev):
56    """cfg80211/mac80211 BSS leak on deauthentication"""
57    return _test_kernel_bss_leak(dev, apdev, deauth=True)
58
59def test_kernel_bss_leak_timeout(dev, apdev):
60    """cfg80211/mac80211 BSS leak on timeout"""
61    return _test_kernel_bss_leak(dev, apdev, deauth=False)
62
63MGMT_SUBTYPE_ACTION = 13
64
65def expect_no_ack(hapd):
66    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
67    if ev is None:
68        raise Exception("Missing TX status")
69    if "ok=0" not in ev:
70        raise Exception("Action frame unexpectedly acknowledged")
71
72def test_kernel_unknown_action_frame_rejection_sta(dev, apdev, params):
73    """mac80211 and unknown Action frame rejection in STA mode"""
74    hapd = hostapd.add_ap(apdev[0], {"ssid": "unknown-action"})
75    dev[0].connect("unknown-action", key_mgmt="NONE", scan_freq="2412")
76    bssid = hapd.own_addr()
77    addr = dev[0].own_addr()
78
79    hapd.set("ext_mgmt_frame_handling", "1")
80
81    # Unicast Action frame with unknown category (response expected)
82    msg = {}
83    msg['fc'] = MGMT_SUBTYPE_ACTION << 4
84    msg['da'] = addr
85    msg['sa'] = bssid
86    msg['bssid'] = bssid
87    msg['payload'] = struct.pack("<BB", 0x70, 0)
88    hapd.mgmt_tx(msg)
89    expect_ack(hapd)
90
91    # Note: mac80211 does not allow group-addressed Action frames in unknown
92    # categories to be transmitted in AP mode, so for now, these steps are
93    # commented out.
94
95    # Multicast Action frame with unknown category (no response expected)
96    #msg['da'] = "01:ff:ff:ff:ff:ff"
97    #msg['payload'] = struct.pack("<BB", 0x71, 1)
98    #hapd.mgmt_tx(msg)
99    #expect_no_ack(hapd)
100
101    # Broadcast Action frame with unknown category (no response expected)
102    #msg['da'] = "ff:ff:ff:ff:ff:ff"
103    #msg['payload'] = struct.pack("<BB", 0x72, 2)
104    #hapd.mgmt_tx(msg)
105    #expect_no_ack(hapd)
106
107    # Unicast Action frame with error indication category (no response expected)
108    msg['da'] = addr
109    msg['payload'] = struct.pack("<BB", 0xf3, 3)
110    hapd.mgmt_tx(msg)
111    expect_ack(hapd)
112
113    # Unicast Action frame with unknown category (response expected)
114    msg['da'] = addr
115    msg['payload'] = struct.pack("<BB", 0x74, 4)
116    hapd.mgmt_tx(msg)
117    expect_ack(hapd)
118
119    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
120                     "wlan.sa == %s && wlan.fc.type_subtype == 0x0d" % addr,
121                     display=["wlan_mgt.fixed.category_code"])
122    res = out.splitlines()
123    categ = [int(x) for x in res]
124
125    if 0xf2 in categ or 0xf3 in categ:
126        raise Exception("Unexpected Action frame rejection: " + str(categ))
127    if 0xf0 not in categ or 0xf4 not in categ:
128        raise Exception("Action frame rejection missing: " + str(categ))
129