999 lines · 28.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * KUnit tests for inform_bss functions * * Copyright (C) 2023-2024 Intel Corporation */#include <linux/ieee80211.h>#include <net/cfg80211.h>#include <kunit/test.h>#include <kunit/skbuff.h>#include "../core.h"#include "util.h" /* mac80211 helpers for element building */#include "../../mac80211/ieee80211_i.h" MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); struct test_elem {	u8 id;	u8 len;	union {		u8 data[255];		struct {			u8 eid;			u8 edata[254];		};	};}; static struct gen_new_ie_case {	const char *desc;	struct test_elem parent_ies[16];	struct test_elem child_ies[16];	struct test_elem result_ies[16];} gen_new_ie_cases[] = {	{		.desc = "ML not inherited",		.parent_ies = {			{ .id = WLAN_EID_EXTENSION, .len = 255,			  .eid = WLAN_EID_EXT_EHT_MULTI_LINK },		},		.child_ies = {			{ .id = WLAN_EID_SSID, .len = 2 },		},		.result_ies = {			{ .id = WLAN_EID_SSID, .len = 2 },		},	},	{		.desc = "fragments are ignored if previous len not 255",		.parent_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 254, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },		},		.child_ies = {			{ .id = WLAN_EID_SSID, .len = 2 },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },		},		.result_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 254, },			{ .id = WLAN_EID_SSID, .len = 2 },		},	},	{		.desc = "fragments inherited",		.parent_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },		},		.child_ies = {			{ .id = WLAN_EID_SSID, .len = 2 },		},		.result_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },			{ .id = WLAN_EID_SSID, .len = 2 },		},	},	{		.desc = "fragments copied",		.parent_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },		},		.child_ies = {			{ .id = WLAN_EID_SSID, .len = 2 },		},		.result_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },			{ .id = WLAN_EID_SSID, .len = 2 },		},	},	{		.desc = "multiple elements inherit",		.parent_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 123, },		},		.child_ies = {			{ .id = WLAN_EID_SSID, .len = 2 },		},		.result_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 123, },			{ .id = WLAN_EID_SSID, .len = 2 },		},	},	{		.desc = "one child element overrides",		.parent_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 255, },			{ .id = WLAN_EID_FRAGMENT, .len = 125, },			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 123, },		},		.child_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 127, },			{ .id = WLAN_EID_SSID, .len = 2 },		},		.result_ies = {			{ .id = WLAN_EID_REDUCED_NEIGHBOR_REPORT, .len = 127, },			{ .id = WLAN_EID_SSID, .len = 2 },		},	},	{		.desc = "empty elements from parent",		.parent_ies = {			{ .id = 0x1, .len = 0, },			{ .id = WLAN_EID_EXTENSION, .len = 1, .eid = 0x10 },		},		.child_ies = {		},		.result_ies = {			{ .id = 0x1, .len = 0, },			{ .id = WLAN_EID_EXTENSION, .len = 1, .eid = 0x10 },		},	},	{		.desc = "empty elements from child",		.parent_ies = {		},		.child_ies = {			{ .id = 0x1, .len = 0, },			{ .id = WLAN_EID_EXTENSION, .len = 1, .eid = 0x10 },		},		.result_ies = {			{ .id = 0x1, .len = 0, },			{ .id = WLAN_EID_EXTENSION, .len = 1, .eid = 0x10 },		},	},	{		.desc = "invalid extended elements ignored",		.parent_ies = {			{ .id = WLAN_EID_EXTENSION, .len = 0 },		},		.child_ies = {			{ .id = WLAN_EID_EXTENSION, .len = 0 },		},		.result_ies = {		},	},	{		.desc = "multiple extended elements",		.parent_ies = {			{ .id = WLAN_EID_EXTENSION, .len = 3,			  .eid = WLAN_EID_EXT_HE_CAPABILITY },			{ .id = WLAN_EID_EXTENSION, .len = 5,			  .eid = WLAN_EID_EXT_ASSOC_DELAY_INFO },			{ .id = WLAN_EID_EXTENSION, .len = 7,			  .eid = WLAN_EID_EXT_HE_OPERATION },			{ .id = WLAN_EID_EXTENSION, .len = 11,			  .eid = WLAN_EID_EXT_FILS_REQ_PARAMS },		},		.child_ies = {			{ .id = WLAN_EID_SSID, .len = 13 },			{ .id = WLAN_EID_EXTENSION, .len = 17,			  .eid = WLAN_EID_EXT_HE_CAPABILITY },			{ .id = WLAN_EID_EXTENSION, .len = 11,			  .eid = WLAN_EID_EXT_FILS_KEY_CONFIRM },			{ .id = WLAN_EID_EXTENSION, .len = 19,			  .eid = WLAN_EID_EXT_HE_OPERATION },		},		.result_ies = {			{ .id = WLAN_EID_EXTENSION, .len = 17,			  .eid = WLAN_EID_EXT_HE_CAPABILITY },			{ .id = WLAN_EID_EXTENSION, .len = 5,			  .eid = WLAN_EID_EXT_ASSOC_DELAY_INFO },			{ .id = WLAN_EID_EXTENSION, .len = 19,			  .eid = WLAN_EID_EXT_HE_OPERATION },			{ .id = WLAN_EID_EXTENSION, .len = 11,			  .eid = WLAN_EID_EXT_FILS_REQ_PARAMS },			{ .id = WLAN_EID_SSID, .len = 13 },			{ .id = WLAN_EID_EXTENSION, .len = 11,			  .eid = WLAN_EID_EXT_FILS_KEY_CONFIRM },		},	},	{		.desc = "non-inherit element",		.parent_ies = {			{ .id = 0x1, .len = 7, },			{ .id = 0x2, .len = 11, },			{ .id = 0x3, .len = 13, },			{ .id = WLAN_EID_EXTENSION, .len = 17, .eid = 0x10 },			{ .id = WLAN_EID_EXTENSION, .len = 19, .eid = 0x11 },			{ .id = WLAN_EID_EXTENSION, .len = 23, .eid = 0x12 },			{ .id = WLAN_EID_EXTENSION, .len = 29, .eid = 0x14 },		},		.child_ies = {			{ .id = WLAN_EID_EXTENSION,			  .eid = WLAN_EID_EXT_NON_INHERITANCE,			  .len = 10,			  .edata = { 0x3, 0x1, 0x2, 0x3,				     0x4, 0x10, 0x11, 0x13, 0x14 } },			{ .id = WLAN_EID_SSID, .len = 2 },		},		.result_ies = {			{ .id = WLAN_EID_EXTENSION, .len = 23, .eid = 0x12 },			{ .id = WLAN_EID_SSID, .len = 2 },		},	},};KUNIT_ARRAY_PARAM_DESC(gen_new_ie, gen_new_ie_cases, desc) static void test_gen_new_ie(struct kunit *test){	const struct gen_new_ie_case *params = test->param_value;	struct sk_buff *parent = kunit_zalloc_skb(test, 1024, GFP_KERNEL);	struct sk_buff *child = kunit_zalloc_skb(test, 1024, GFP_KERNEL);	struct sk_buff *reference = kunit_zalloc_skb(test, 1024, GFP_KERNEL);	u8 *out = kunit_kzalloc(test, IEEE80211_MAX_DATA_LEN, GFP_KERNEL);	size_t len;	int i; 	KUNIT_ASSERT_NOT_NULL(test, parent);	KUNIT_ASSERT_NOT_NULL(test, child);	KUNIT_ASSERT_NOT_NULL(test, reference);	KUNIT_ASSERT_NOT_NULL(test, out); 	for (i = 0; i < ARRAY_SIZE(params->parent_ies); i++) {		if (params->parent_ies[i].len != 0) {			skb_put_u8(parent, params->parent_ies[i].id);			skb_put_u8(parent, params->parent_ies[i].len);			skb_put_data(parent, params->parent_ies[i].data,				     params->parent_ies[i].len);		} 		if (params->child_ies[i].len != 0) {			skb_put_u8(child, params->child_ies[i].id);			skb_put_u8(child, params->child_ies[i].len);			skb_put_data(child, params->child_ies[i].data,				     params->child_ies[i].len);		} 		if (params->result_ies[i].len != 0) {			skb_put_u8(reference, params->result_ies[i].id);			skb_put_u8(reference, params->result_ies[i].len);			skb_put_data(reference, params->result_ies[i].data,				     params->result_ies[i].len);		}	} 	len = cfg80211_gen_new_ie(parent->data, parent->len,				  child->data, child->len,				  out, IEEE80211_MAX_DATA_LEN);	KUNIT_EXPECT_EQ(test, len, reference->len);	KUNIT_EXPECT_MEMEQ(test, out, reference->data, reference->len);	memset(out, 0, IEEE80211_MAX_DATA_LEN); 	/* Exactly enough space */	len = cfg80211_gen_new_ie(parent->data, parent->len,				  child->data, child->len,				  out, reference->len);	KUNIT_EXPECT_EQ(test, len, reference->len);	KUNIT_EXPECT_MEMEQ(test, out, reference->data, reference->len);	memset(out, 0, IEEE80211_MAX_DATA_LEN); 	/* Not enough space (or expected zero length) */	len = cfg80211_gen_new_ie(parent->data, parent->len,				  child->data, child->len,				  out, reference->len - 1);	KUNIT_EXPECT_EQ(test, len, 0);} static void test_gen_new_ie_malformed(struct kunit *test){	struct sk_buff *malformed = kunit_zalloc_skb(test, 1024, GFP_KERNEL);	u8 *out = kunit_kzalloc(test, IEEE80211_MAX_DATA_LEN, GFP_KERNEL);	size_t len; 	KUNIT_ASSERT_NOT_NULL(test, malformed);	KUNIT_ASSERT_NOT_NULL(test, out); 	skb_put_u8(malformed, WLAN_EID_SSID);	skb_put_u8(malformed, 3);	skb_put(malformed, 3);	skb_put_u8(malformed, WLAN_EID_REDUCED_NEIGHBOR_REPORT);	skb_put_u8(malformed, 10);	skb_put(malformed, 9); 	len = cfg80211_gen_new_ie(malformed->data, malformed->len,				  out, 0,				  out, IEEE80211_MAX_DATA_LEN);	KUNIT_EXPECT_EQ(test, len, 5); 	len = cfg80211_gen_new_ie(out, 0,				  malformed->data, malformed->len,				  out, IEEE80211_MAX_DATA_LEN);	KUNIT_EXPECT_EQ(test, len, 5);} struct inform_bss {	struct kunit *test; 	int inform_bss_count;}; static void inform_bss_inc_counter(struct wiphy *wiphy,				   struct cfg80211_bss *bss,				   const struct cfg80211_bss_ies *ies,				   void *drv_data){	struct inform_bss *ctx = t_wiphy_ctx(wiphy); 	ctx->inform_bss_count++; 	rcu_read_lock();	KUNIT_EXPECT_PTR_EQ(ctx->test, drv_data, ctx);	KUNIT_EXPECT_PTR_EQ(ctx->test, ies, rcu_dereference(bss->ies));	rcu_read_unlock();} static void test_inform_bss_ssid_only(struct kunit *test){	struct inform_bss ctx = {		.test = test,	};	struct wiphy *wiphy = T_WIPHY(test, ctx);	struct t_wiphy_priv *w_priv = wiphy_priv(wiphy);	struct cfg80211_inform_bss inform_bss = {		.signal = 50,		.drv_data = &ctx,	};	const u8 bssid[ETH_ALEN] = { 0x10, 0x22, 0x33, 0x44, 0x55, 0x66 };	u64 tsf = 0x1000000000000000ULL;	int beacon_int = 100;	u16 capability = 0x1234;	static const u8 input[] = {		[0] = WLAN_EID_SSID,		[1] = 4,		[2] = 'T', 'E', 'S', 'T'	};	struct cfg80211_bss *bss, *other;	const struct cfg80211_bss_ies *ies; 	w_priv->ops->inform_bss = inform_bss_inc_counter; 	inform_bss.chan = ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(2412));	KUNIT_ASSERT_NOT_NULL(test, inform_bss.chan); 	bss = cfg80211_inform_bss_data(wiphy, &inform_bss,				       CFG80211_BSS_FTYPE_PRESP, bssid, tsf,				       capability, beacon_int,				       input, sizeof(input),				       GFP_KERNEL);	KUNIT_EXPECT_NOT_NULL(test, bss);	KUNIT_EXPECT_EQ(test, ctx.inform_bss_count, 1); 	/* Check values in returned bss are correct */	KUNIT_EXPECT_EQ(test, bss->signal, inform_bss.signal);	KUNIT_EXPECT_EQ(test, bss->beacon_interval, beacon_int);	KUNIT_EXPECT_EQ(test, bss->capability, capability);	KUNIT_EXPECT_EQ(test, bss->bssid_index, 0);	KUNIT_EXPECT_PTR_EQ(test, bss->channel, inform_bss.chan);	KUNIT_EXPECT_MEMEQ(test, bssid, bss->bssid, sizeof(bssid)); 	/* Check the IEs have the expected value */	rcu_read_lock();	ies = rcu_dereference(bss->ies);	KUNIT_EXPECT_NOT_NULL(test, ies);	KUNIT_EXPECT_EQ(test, ies->tsf, tsf);	KUNIT_EXPECT_EQ(test, ies->len, sizeof(input));	KUNIT_EXPECT_MEMEQ(test, ies->data, input, sizeof(input));	rcu_read_unlock(); 	/* Check we can look up the BSS - by SSID */	other = cfg80211_get_bss(wiphy, NULL, NULL, "TEST", 4,				 IEEE80211_BSS_TYPE_ANY,				 IEEE80211_PRIVACY_ANY);	KUNIT_EXPECT_PTR_EQ(test, bss, other);	cfg80211_put_bss(wiphy, other); 	/* Check we can look up the BSS - by BSSID */	other = cfg80211_get_bss(wiphy, NULL, bssid, NULL, 0,				 IEEE80211_BSS_TYPE_ANY,				 IEEE80211_PRIVACY_ANY);	KUNIT_EXPECT_PTR_EQ(test, bss, other);	cfg80211_put_bss(wiphy, other); 	cfg80211_put_bss(wiphy, bss);} static void test_get_bss_miss_reason(struct kunit *test){	struct inform_bss ctx = {		.test = test,	};	struct wiphy *wiphy = T_WIPHY(test, ctx);	struct cfg80211_inform_bss inform_bss = {		.signal = 50,		.drv_data = &ctx,	};	const u8 bssid[ETH_ALEN] = { 0x10, 0x22, 0x33, 0x44, 0x55, 0x66 };	const u8 other_bssid[ETH_ALEN] = { 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 };	static const u8 ies[] = {		[0] = WLAN_EID_SSID,		[1] = 4,		[2] = 'T', 'E', 'S', 'T'	};	struct cfg80211_internal_bss *ibss;	struct netlink_ext_ack extack = {};	struct cfg80211_bss *bss, *bss2, *found; 	inform_bss.chan = ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(2412));	KUNIT_ASSERT_NOT_NULL(test, inform_bss.chan); 	bss = cfg80211_inform_bss_data(wiphy, &inform_bss,				       CFG80211_BSS_FTYPE_PRESP, bssid, 0,				       0x1234, 100, ies, sizeof(ies),				       GFP_KERNEL);	KUNIT_ASSERT_NOT_NULL(test, bss);	ibss = container_of(bss, struct cfg80211_internal_bss, pub); 	/* Fresh usable entry: found, no message is set */	found = __cfg80211_get_bss(wiphy, NULL, bssid, NULL, 0,				   IEEE80211_BSS_TYPE_ANY,				   IEEE80211_PRIVACY_ANY,				   NL80211_BSS_USE_FOR_NORMAL, &extack);	KUNIT_ASSERT_PTR_EQ(test, found, bss);	KUNIT_EXPECT_NULL(test, extack._msg);	cfg80211_put_bss(wiphy, found); 	/* No entry at all for this BSSID */	found = __cfg80211_get_bss(wiphy, NULL, other_bssid, NULL, 0,				   IEEE80211_BSS_TYPE_ANY,				   IEEE80211_PRIVACY_ANY,				   NL80211_BSS_USE_FOR_NORMAL, &extack);	KUNIT_EXPECT_NULL(test, found);	KUNIT_EXPECT_STREQ(test, extack._msg, "BSS not found in scan results"); 	/* Fresh entry that is not usable for the requested use */	extack._msg = NULL;	bss->use_for = 0;	found = __cfg80211_get_bss(wiphy, NULL, bssid, NULL, 0,				   IEEE80211_BSS_TYPE_ANY,				   IEEE80211_PRIVACY_ANY,				   NL80211_BSS_USE_FOR_NORMAL, &extack);	KUNIT_EXPECT_NULL(test, found);	KUNIT_EXPECT_STREQ(test, extack._msg,			   "BSS cannot be used for the requested operation");	bss->use_for = NL80211_BSS_USE_FOR_ALL; 	/* Expired entry, > IEEE80211_SCAN_RESULT_EXPIRE (30s) old */	extack._msg = NULL;	ibss->ts = jiffies - 60 * HZ;	found = __cfg80211_get_bss(wiphy, NULL, bssid, NULL, 0,				   IEEE80211_BSS_TYPE_ANY,				   IEEE80211_PRIVACY_ANY,				   NL80211_BSS_USE_FOR_NORMAL, &extack);	KUNIT_EXPECT_NULL(test, found);	KUNIT_EXPECT_STREQ(test, extack._msg,			   "BSS entry in scan results is expired"); 	/* An entry both expired and unusable reports expired */	extack._msg = NULL;	bss->use_for = 0;	found = __cfg80211_get_bss(wiphy, NULL, bssid, NULL, 0,				   IEEE80211_BSS_TYPE_ANY,				   IEEE80211_PRIVACY_ANY,				   NL80211_BSS_USE_FOR_NORMAL, &extack);	KUNIT_EXPECT_NULL(test, found);	KUNIT_EXPECT_STREQ(test, extack._msg,			   "BSS entry in scan results is expired");	bss->use_for = NL80211_BSS_USE_FOR_ALL; 	/* Expired but held entries are still usable, no message is set */	extack._msg = NULL;	atomic_set(&ibss->hold, 1);	found = __cfg80211_get_bss(wiphy, NULL, bssid, NULL, 0,				   IEEE80211_BSS_TYPE_ANY,				   IEEE80211_PRIVACY_ANY,				   NL80211_BSS_USE_FOR_NORMAL, &extack);	KUNIT_ASSERT_PTR_EQ(test, found, bss);	KUNIT_EXPECT_NULL(test, extack._msg);	cfg80211_put_bss(wiphy, found);	atomic_set(&ibss->hold, 0); 	/*

Lines 1–500 of 999.