File Index
Files and directories
Sign in
FILE

chan-mode.c

File preview with syntax highlighting.

linux-6.19.14/net/mac80211/tests/chan-mode.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * KUnit tests for channel mode functions
  4 *
  5 * Copyright (C) 2024-2025 Intel Corporation
  6 */
  7#include <net/cfg80211.h>
  8#include <kunit/test.h>
  9
 10#include "util.h"
 11
 12MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
 13
 14static const struct determine_chan_mode_case {
 15	const char *desc;
 16	u8 extra_supp_rate;
 17	enum ieee80211_conn_mode conn_mode;
 18	enum ieee80211_conn_mode expected_mode;
 19	bool strict;
 20	u8 userspace_selector;
 21	struct ieee80211_ht_cap ht_capa_mask;
 22	struct ieee80211_vht_cap vht_capa;
 23	struct ieee80211_vht_cap vht_capa_mask;
 24	u8 vht_basic_mcs_1_4_set:1,
 25	   vht_basic_mcs_5_8_set:1,
 26	   he_basic_mcs_1_4_set:1,
 27	   he_basic_mcs_5_8_set:1;
 28	u8 vht_basic_mcs_1_4, vht_basic_mcs_5_8;
 29	u8 he_basic_mcs_1_4, he_basic_mcs_5_8;
 30	u8 eht_mcs7_min_nss;
 31	u16 eht_disabled_subchannels;
 32	u8 eht_bw;
 33	enum ieee80211_conn_bw_limit conn_bw_limit;
 34	enum ieee80211_conn_bw_limit expected_bw_limit;
 35	int error;
 36} determine_chan_mode_cases[] = {
 37	{
 38		.desc = "Normal case, EHT is working",
 39		.conn_mode = IEEE80211_CONN_MODE_EHT,
 40		.expected_mode = IEEE80211_CONN_MODE_EHT,
 41	}, {
 42		.desc = "Requiring EHT support is fine",
 43		.conn_mode = IEEE80211_CONN_MODE_EHT,
 44		.expected_mode = IEEE80211_CONN_MODE_EHT,
 45		.extra_supp_rate = 0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY,
 46	}, {
 47		.desc = "Lowering the mode limits us",
 48		.conn_mode = IEEE80211_CONN_MODE_VHT,
 49		.expected_mode = IEEE80211_CONN_MODE_VHT,
 50	}, {
 51		.desc = "Requesting a basic rate/selector that we do not support",
 52		.conn_mode = IEEE80211_CONN_MODE_EHT,
 53		.extra_supp_rate = 0x80 | (BSS_MEMBERSHIP_SELECTOR_MIN - 1),
 54		.error = EINVAL,
 55	}, {
 56		.desc = "As before, but userspace says it is taking care of it",
 57		.conn_mode = IEEE80211_CONN_MODE_EHT,
 58		.userspace_selector = BSS_MEMBERSHIP_SELECTOR_MIN - 1,
 59		.extra_supp_rate = 0x80 | (BSS_MEMBERSHIP_SELECTOR_MIN - 1),
 60		.expected_mode = IEEE80211_CONN_MODE_EHT,
 61	}, {
 62		.desc = "Masking out a supported rate in HT capabilities",
 63		.conn_mode = IEEE80211_CONN_MODE_EHT,
 64		.expected_mode = IEEE80211_CONN_MODE_LEGACY,
 65		.ht_capa_mask = {
 66			.mcs.rx_mask[0] = 0xf7,
 67		},
 68	}, {
 69		.desc = "Masking out a RX rate in VHT capabilities",
 70		.conn_mode = IEEE80211_CONN_MODE_EHT,
 71		.expected_mode = IEEE80211_CONN_MODE_HT,
 72		/* Only one RX stream at MCS 0-7 */
 73		.vht_capa = {
 74			.supp_mcs.rx_mcs_map =
 75				cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_7),
 76		},
 77		.vht_capa_mask = {
 78			.supp_mcs.rx_mcs_map = cpu_to_le16(0xffff),
 79		},
 80		.strict = true,
 81	}, {
 82		.desc = "Masking out a TX rate in VHT capabilities",
 83		.conn_mode = IEEE80211_CONN_MODE_EHT,
 84		.expected_mode = IEEE80211_CONN_MODE_HT,
 85		/* Only one TX stream at MCS 0-7 */
 86		.vht_capa = {
 87			.supp_mcs.tx_mcs_map =
 88				cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_7),
 89		},
 90		.vht_capa_mask = {
 91			.supp_mcs.tx_mcs_map = cpu_to_le16(0xffff),
 92		},
 93		.strict = true,
 94	}, {
 95		.desc = "AP has higher VHT requirement than client",
 96		.conn_mode = IEEE80211_CONN_MODE_EHT,
 97		.expected_mode = IEEE80211_CONN_MODE_HT,
 98		.vht_basic_mcs_5_8_set = 1,
 99		.vht_basic_mcs_5_8 = 0xFE, /* require 5th stream */
100		.strict = true,
101	}, {
102		.desc = "all zero VHT basic rates are ignored (many APs broken)",
103		.conn_mode = IEEE80211_CONN_MODE_VHT,
104		.expected_mode = IEEE80211_CONN_MODE_VHT,
105		.vht_basic_mcs_1_4_set = 1,
106		.vht_basic_mcs_5_8_set = 1,
107	}, {
108		.desc = "AP requires 3 HE streams but client only has two",
109		.conn_mode = IEEE80211_CONN_MODE_EHT,
110		.expected_mode = IEEE80211_CONN_MODE_VHT,
111		.he_basic_mcs_1_4 = 0b11001010,
112		.he_basic_mcs_1_4_set = 1,
113	}, {
114		.desc = "all zero HE basic rates are ignored (iPhone workaround)",
115		.conn_mode = IEEE80211_CONN_MODE_HE,
116		.expected_mode = IEEE80211_CONN_MODE_HE,
117		.he_basic_mcs_1_4_set = 1,
118		.he_basic_mcs_5_8_set = 1,
119	}, {
120		.desc = "AP requires too many RX streams with EHT MCS 7",
121		.conn_mode = IEEE80211_CONN_MODE_EHT,
122		.expected_mode = IEEE80211_CONN_MODE_HE,
123		.eht_mcs7_min_nss = 0x15,
124	}, {
125		.desc = "AP requires too many TX streams with EHT MCS 7",
126		.conn_mode = IEEE80211_CONN_MODE_EHT,
127		.expected_mode = IEEE80211_CONN_MODE_HE,
128		.eht_mcs7_min_nss = 0x51,
129	}, {
130		.desc = "AP requires too many RX streams with EHT MCS 7 and EHT is required",
131		.extra_supp_rate = 0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY,
132		.conn_mode = IEEE80211_CONN_MODE_EHT,
133		.eht_mcs7_min_nss = 0x15,
134		.error = EINVAL,
135	}, {
136		.desc = "80 MHz EHT is downgraded to 40 MHz HE due to puncturing",
137		.conn_mode = IEEE80211_CONN_MODE_EHT,
138		.expected_mode = IEEE80211_CONN_MODE_HE,
139		.conn_bw_limit = IEEE80211_CONN_BW_LIMIT_80,
140		.expected_bw_limit = IEEE80211_CONN_BW_LIMIT_40,
141		.eht_disabled_subchannels = 0x08,
142		.eht_bw = IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ,
143	}
144};
145KUNIT_ARRAY_PARAM_DESC(determine_chan_mode, determine_chan_mode_cases, desc)
146
147static void test_determine_chan_mode(struct kunit *test)
148{
149	const struct determine_chan_mode_case *params = test->param_value;
150	struct t_sdata *t_sdata = T_SDATA(test);
151	struct ieee80211_conn_settings conn = {
152		.mode = params->conn_mode,
153		.bw_limit = params->conn_bw_limit,
154	};
155	struct cfg80211_bss cbss = {
156		.channel = &t_sdata->band_5ghz.channels[0],
157	};
158	unsigned long userspace_selectors[BITS_TO_LONGS(128)] = {};
159	u8 bss_ies[] = {
160		/* Supported Rates */
161		WLAN_EID_SUPP_RATES, 0x08,
162		0x82, 0x84, 0x8b, 0x96, 0xc, 0x12, 0x18, 0x24,
163		/* Extended Supported Rates */
164		WLAN_EID_EXT_SUPP_RATES, 0x05,
165		0x30, 0x48, 0x60, 0x6c, params->extra_supp_rate,
166		/* HT Capabilities */
167		WLAN_EID_HT_CAPABILITY, 0x1a,
168		0x0c, 0x00, 0x1b, 0xff, 0xff, 0x00, 0x00, 0x00,
169		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
170		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171		0x00, 0x00,
172		/* HT Information (0xff for 1 stream) */
173		WLAN_EID_HT_OPERATION, 0x16,
174		0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
175		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177		/* VHT Capabilities */
178		WLAN_EID_VHT_CAPABILITY, 0xc,
179		0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
180		0xff, 0xff, 0x00, 0x00,
181		/* VHT Operation */
182		WLAN_EID_VHT_OPERATION, 0x05,
183		0x00, 0x00, 0x00,
184		params->vht_basic_mcs_1_4_set ?
185			params->vht_basic_mcs_1_4 :
186			le16_get_bits(t_sdata->band_5ghz.vht_cap.vht_mcs.rx_mcs_map, 0xff),
187		params->vht_basic_mcs_5_8_set ?
188			params->vht_basic_mcs_5_8 :
189			le16_get_bits(t_sdata->band_5ghz.vht_cap.vht_mcs.rx_mcs_map, 0xff00),
190		/* HE Capabilities */
191		WLAN_EID_EXTENSION, 0x16, WLAN_EID_EXT_HE_CAPABILITY,
192		0x01, 0x78, 0xc8, 0x1a, 0x40, 0x00, 0x00, 0xbf,
193		0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194		0x00, 0xfa, 0xff, 0xfa, 0xff,
195		/* HE Operation (permit overriding values) */
196		WLAN_EID_EXTENSION, 0x07, WLAN_EID_EXT_HE_OPERATION,
197		0xf0, 0x3f, 0x00, 0xb0,
198		params->he_basic_mcs_1_4_set ? params->he_basic_mcs_1_4 : 0xfc,
199		params->he_basic_mcs_5_8_set ? params->he_basic_mcs_5_8 : 0xff,
200		/* EHT Capabilities */
201		WLAN_EID_EXTENSION, 0x12, WLAN_EID_EXT_EHT_CAPABILITY,
202		0x07, 0x00, 0x1c, 0x00, 0x00, 0xfe, 0xff, 0xff,
203		0x7f, 0x01, 0x00, 0x88, 0x88, 0x88, 0x00, 0x00,
204		0x00,
205		/* EHT Operation */
206		WLAN_EID_EXTENSION, 0x0b, WLAN_EID_EXT_EHT_OPERATION,
207		0x03, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11,
208		0x00, 0x00, 0x00, params->eht_bw,
209		params->eht_bw == IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ ? 42 : 36,
210		0x00,
211		u16_get_bits(params->eht_disabled_subchannels, 0xff),
212		u16_get_bits(params->eht_disabled_subchannels, 0xff00),
213	};
214	struct ieee80211_chan_req chanreq = {};
215	struct cfg80211_chan_def ap_chandef = {};
216	struct ieee802_11_elems *elems;
217
218	/* To force EHT downgrade to HE on punctured 80 MHz downgraded to 40 MHz */
219	set_bit(IEEE80211_HW_DISALLOW_PUNCTURING, t_sdata->local.hw.flags);
220
221	if (params->strict)
222		set_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags);
223	else
224		clear_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags);
225
226	t_sdata->sdata->u.mgd.ht_capa_mask = params->ht_capa_mask;
227	t_sdata->sdata->u.mgd.vht_capa = params->vht_capa;
228	t_sdata->sdata->u.mgd.vht_capa_mask = params->vht_capa_mask;
229
230	if (params->userspace_selector)
231		set_bit(params->userspace_selector, userspace_selectors);
232
233	rcu_assign_pointer(cbss.ies,
234			   kunit_kzalloc(test,
235					 sizeof(cbss) + sizeof(bss_ies),
236					 GFP_KERNEL));
237	KUNIT_ASSERT_NOT_NULL(test, rcu_access_pointer(cbss.ies));
238	((struct cfg80211_bss_ies *)rcu_access_pointer(cbss.ies))->len = sizeof(bss_ies);
239
240	memcpy((void *)rcu_access_pointer(cbss.ies)->data, bss_ies,
241	       sizeof(bss_ies));
242
243	rcu_read_lock();
244	elems = ieee80211_determine_chan_mode(t_sdata->sdata, &conn, &cbss,
245					      0, &chanreq, &ap_chandef,
246					      userspace_selectors);
247	rcu_read_unlock();
248
249	/* We do not need elems, free them if they are valid. */
250	if (!IS_ERR_OR_NULL(elems))
251		kfree(elems);
252
253	if (params->error) {
254		KUNIT_ASSERT_TRUE(test, IS_ERR(elems));
255		KUNIT_ASSERT_EQ(test, PTR_ERR(elems), -params->error);
256	} else {
257		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, elems);
258		KUNIT_ASSERT_EQ(test, conn.mode, params->expected_mode);
259		KUNIT_ASSERT_EQ(test, conn.bw_limit, params->expected_bw_limit);
260	}
261}
262
263static struct kunit_case chan_mode_cases[] = {
264	KUNIT_CASE_PARAM(test_determine_chan_mode,
265			 determine_chan_mode_gen_params),
266	{}
267};
268
269static struct kunit_suite chan_mode = {
270	.name = "mac80211-mlme-chan-mode",
271	.test_cases = chan_mode_cases,
272};
273
274kunit_test_suite(chan_mode);
~/ Read-only file preview.