From: Benjamin Berg benjamin.berg@intel.com
This patchset adds a couple of helpers for kunit as well as tests for cfg80211 and mac80211 that use them.
Benjamin Berg (3): kunit: add parameter generation macro using description from array kunit: add a convenience allocation wrapper for SKBs wifi: cfg80211: tests: add some scanning related tests
Johannes Berg (3): wifi: mac80211: add kunit tests for public action handling wifi: mac80211: kunit: generalize public action test wifi: mac80211: kunit: extend MFP tests
Documentation/dev-tools/kunit/usage.rst | 12 +- include/kunit/skbuff.h | 56 +++ include/kunit/test.h | 19 + net/mac80211/ieee80211_i.h | 10 + net/mac80211/rx.c | 4 +- net/mac80211/tests/Makefile | 2 +- net/mac80211/tests/mfp.c | 286 +++++++++++ net/wireless/core.h | 13 +- net/wireless/scan.c | 9 +- net/wireless/tests/Makefile | 2 +- net/wireless/tests/scan.c | 625 ++++++++++++++++++++++++ net/wireless/tests/util.c | 56 +++ net/wireless/tests/util.h | 66 +++ 13 files changed, 1145 insertions(+), 15 deletions(-) create mode 100644 include/kunit/skbuff.h create mode 100644 net/mac80211/tests/mfp.c create mode 100644 net/wireless/tests/scan.c create mode 100644 net/wireless/tests/util.c create mode 100644 net/wireless/tests/util.h
From: Benjamin Berg benjamin.berg@intel.com
The existing KUNIT_ARRAY_PARAM macro requires a separate function to get the description. However, in a lot of cases the description can just be copied directly from the array. Add a second macro that avoids having to write a static function just for a single strscpy.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com --- Documentation/dev-tools/kunit/usage.rst | 12 ++++-------- include/kunit/test.h | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index c27e1646ecd9..b959e5befcbe 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -566,13 +566,9 @@ By reusing the same ``cases`` array from above, we can write the test as a }, };
- // Need a helper function to generate a name for each test case. - static void case_to_desc(const struct sha1_test_case *t, char *desc) - { - strcpy(desc, t->str); - } - // Creates `sha1_gen_params()` to iterate over `cases`. - KUNIT_ARRAY_PARAM(sha1, cases, case_to_desc); + // Creates `sha1_gen_params()` to iterate over `cases` while using + // the struct member `str` for the case description. + KUNIT_ARRAY_PARAM_DESC(sha1, cases, str);
// Looks no different from a normal test. static void sha1_test(struct kunit *test) @@ -588,7 +584,7 @@ By reusing the same ``cases`` array from above, we can write the test as a }
// Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the - // function declared by KUNIT_ARRAY_PARAM. + // function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC. static struct kunit_case sha1_test_cases[] = { KUNIT_CASE_PARAM(sha1_test, sha1_gen_params), {} diff --git a/include/kunit/test.h b/include/kunit/test.h index 20ed9f9275c9..2dfa851e1f88 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -1514,6 +1514,25 @@ do { \ return NULL; \ }
+/** + * KUNIT_ARRAY_PARAM_DESC() - Define test parameter generator from an array. + * @name: prefix for the test parameter generator function. + * @array: array of test parameters. + * @desc_member: structure member from array element to use as description + * + * Define function @name_gen_params which uses @array to generate parameters. + */ +#define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \ + static const void *name##_gen_params(const void *prev, char *desc) \ + { \ + typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ + if (__next - (array) < ARRAY_SIZE((array))) { \ + strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \ + return __next; \ + } \ + return NULL; \ + } + // TODO(dlatypov@google.com): consider eventually migrating users to explicitly // include resource.h themselves if they need it. #include <kunit/resource.h>
On Wed, 20 Dec 2023 at 23:20, benjamin@sipsolutions.net wrote:
From: Benjamin Berg benjamin.berg@intel.com
The existing KUNIT_ARRAY_PARAM macro requires a separate function to get the description. However, in a lot of cases the description can just be copied directly from the array. Add a second macro that avoids having to write a static function just for a single strscpy.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
I'm generally pretty happy with this, though note the checkpatch warning below.
There was some discussion at plumbers about expanding the parameterised test APIs, so we may need to adjust the implementation of this down the line, but I don't think that'll happen for a while, so don't worry.
With the warnings fixed, this is:
Reviewed-by: David Gow davidgow@google.com
I'm okay with this going in via the wireless tree if that's easier; certainly there are some conflicts with the later patches in this series and the kunit one.
Cheers, -- David
Documentation/dev-tools/kunit/usage.rst | 12 ++++-------- include/kunit/test.h | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index c27e1646ecd9..b959e5befcbe 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -566,13 +566,9 @@ By reusing the same ``cases`` array from above, we can write the test as a }, };
// Need a helper function to generate a name for each test case.
static void case_to_desc(const struct sha1_test_case *t, char *desc)
{
strcpy(desc, t->str);
}
// Creates `sha1_gen_params()` to iterate over `cases`.
KUNIT_ARRAY_PARAM(sha1, cases, case_to_desc);
// Creates `sha1_gen_params()` to iterate over `cases` while using
// the struct member `str` for the case description.
KUNIT_ARRAY_PARAM_DESC(sha1, cases, str); // Looks no different from a normal test. static void sha1_test(struct kunit *test)
@@ -588,7 +584,7 @@ By reusing the same ``cases`` array from above, we can write the test as a }
// Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the
// function declared by KUNIT_ARRAY_PARAM.
// function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC. static struct kunit_case sha1_test_cases[] = { KUNIT_CASE_PARAM(sha1_test, sha1_gen_params), {}
diff --git a/include/kunit/test.h b/include/kunit/test.h index 20ed9f9275c9..2dfa851e1f88 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -1514,6 +1514,25 @@ do { \ return NULL; \ }
+/**
- KUNIT_ARRAY_PARAM_DESC() - Define test parameter generator from an array.
- @name: prefix for the test parameter generator function.
- @array: array of test parameters.
- @desc_member: structure member from array element to use as description
- Define function @name_gen_params which uses @array to generate parameters.
- */
+#define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \
static const void *name##_gen_params(const void *prev, char *desc) \
{ \
typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
checkpatch is complaining here: ERROR: need consistent spacing around '*' (ctx:WxV) #71: FILE: include/kunit/test.h:1528:
+ typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
if (__next - (array) < ARRAY_SIZE((array))) { \
strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \
return __next; \
} \
return NULL; \
}
// TODO(dlatypov@google.com): consider eventually migrating users to explicitly // include resource.h themselves if they need it.
#include <kunit/resource.h>
2.43.0
-- You received this message because you are subscribed to the Google Groups "KUnit Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/20231220151952.415232-2-benjamin....
On Fri, 2023-12-22 at 18:02 +0800, David Gow wrote:
On Wed, 20 Dec 2023 at 23:20, benjamin@sipsolutions.net wrote:
From: Benjamin Berg benjamin.berg@intel.com
The existing KUNIT_ARRAY_PARAM macro requires a separate function to get the description. However, in a lot of cases the description can just be copied directly from the array. Add a second macro that avoids having to write a static function just for a single strscpy.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
I'm generally pretty happy with this, though note the checkpatch warning below.
There was some discussion at plumbers about expanding the parameterised test APIs, so we may need to adjust the implementation of this down the line, but I don't think that'll happen for a while, so don't worry.
With the warnings fixed, this is:
I think the checkpatch warning is a false positive. It seems to confuse the * as a multiplication due to typeof() looking like a function call rather than a variable declaration.
Benjamin
Reviewed-by: David Gow davidgow@google.com
I'm okay with this going in via the wireless tree if that's easier; certainly there are some conflicts with the later patches in this series and the kunit one.
Cheers, -- David
Documentation/dev-tools/kunit/usage.rst | 12 ++++-------- include/kunit/test.h | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index c27e1646ecd9..b959e5befcbe 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -566,13 +566,9 @@ By reusing the same ``cases`` array from above, we can write the test as a }, };
- // Need a helper function to generate a name for each test case. - static void case_to_desc(const struct sha1_test_case *t, char *desc) - { - strcpy(desc, t->str); - } - // Creates `sha1_gen_params()` to iterate over `cases`. - KUNIT_ARRAY_PARAM(sha1, cases, case_to_desc); + // Creates `sha1_gen_params()` to iterate over `cases` while using + // the struct member `str` for the case description. + KUNIT_ARRAY_PARAM_DESC(sha1, cases, str);
// Looks no different from a normal test. static void sha1_test(struct kunit *test) @@ -588,7 +584,7 @@ By reusing the same ``cases`` array from above, we can write the test as a }
// Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the - // function declared by KUNIT_ARRAY_PARAM. + // function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC. static struct kunit_case sha1_test_cases[] = { KUNIT_CASE_PARAM(sha1_test, sha1_gen_params), {} diff --git a/include/kunit/test.h b/include/kunit/test.h index 20ed9f9275c9..2dfa851e1f88 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -1514,6 +1514,25 @@ do { \ return NULL; \ }
+/**
- KUNIT_ARRAY_PARAM_DESC() - Define test parameter generator from
an array.
- @name: prefix for the test parameter generator function.
- @array: array of test parameters.
- @desc_member: structure member from array element to use as
description
- Define function @name_gen_params which uses @array to generate
parameters.
- */
+#define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \ + static const void *name##_gen_params(const void *prev, char *desc) \ + { \ + typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
checkpatch is complaining here: ERROR: need consistent spacing around '*' (ctx:WxV) #71: FILE: include/kunit/test.h:1528:
+ typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
+ if (__next - (array) < ARRAY_SIZE((array))) { \ + strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \ + return __next; \ + } \ + return NULL; \ + }
// TODO(dlatypov@google.com): consider eventually migrating users to explicitly // include resource.h themselves if they need it. #include <kunit/resource.h> -- 2.43.0
-- You received this message because you are subscribed to the Google Groups "KUnit Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/20231220151952.415232-2-benjamin... .
On Fri, 22 Dec 2023 at 23:09, Benjamin Berg benjamin@sipsolutions.net wrote:
On Fri, 2023-12-22 at 18:02 +0800, David Gow wrote:
On Wed, 20 Dec 2023 at 23:20, benjamin@sipsolutions.net wrote:
From: Benjamin Berg benjamin.berg@intel.com
The existing KUNIT_ARRAY_PARAM macro requires a separate function to get the description. However, in a lot of cases the description can just be copied directly from the array. Add a second macro that avoids having to write a static function just for a single strscpy.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
I'm generally pretty happy with this, though note the checkpatch warning below.
There was some discussion at plumbers about expanding the parameterised test APIs, so we may need to adjust the implementation of this down the line, but I don't think that'll happen for a while, so don't worry.
With the warnings fixed, this is:
I think the checkpatch warning is a false positive. It seems to confuse the * as a multiplication due to typeof() looking like a function call rather than a variable declaration.
Benjamin
Ah, yeah: this appears to be due to checkpatch not handling nested () within a typeof().
Reviewed-by: David Gow davidgow@google.com
Cheers, -- David
From: Benjamin Berg benjamin.berg@intel.com
Add a simple convenience helper to allocate and zero fill an SKB for the use by a kunit test. Also provide a way to free it again in case that may be desirable.
This simply mirrors the kunit_kmalloc API.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com --- include/kunit/skbuff.h | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 include/kunit/skbuff.h
diff --git a/include/kunit/skbuff.h b/include/kunit/skbuff.h new file mode 100644 index 000000000000..2144d01e556f --- /dev/null +++ b/include/kunit/skbuff.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Base unit test (KUnit) API. + * + * Copyright (C) 2023 Intel Corporation + */ + +#ifndef _KUNIT_SKBUFF_H +#define _KUNIT_SKBUFF_H + +#include <kunit/resource.h> +#include <linux/skbuff.h> + +static void kunit_action_kfree_skb(void *p) +{ + kfree_skb((struct sk_buff *)p); +} + +/** + * kunit_zalloc_skb() - Allocate and initialize a resource managed skb. + * @test: The test case to which the skb belongs + * @len: size to allocate + * + * Allocate a new struct sk_buff with GFP_KERNEL, zero fill the give length + * and add it as a resource to the kunit test for automatic cleanup. + * + * Returns: newly allocated SKB, or %NULL on error + */ +static inline struct sk_buff *kunit_zalloc_skb(struct kunit *test, int len, + gfp_t gfp) +{ + struct sk_buff *res = alloc_skb(len, GFP_KERNEL); + + if (!res || skb_pad(res, len)) + return NULL; + + if (kunit_add_action_or_reset(test, kunit_action_kfree_skb, res)) + return NULL; + + return res; +} + +/** + * kunit_kfree_skb() - Like kfree_skb except for allocations managed by KUnit. + * @test: The test case to which the resource belongs. + * @skb: The SKB to free. + */ +static inline void kunit_kfree_skb(struct kunit *test, struct sk_buff *skb) +{ + if (!skb) + return; + + kunit_release_action(test, kunit_action_kfree_skb, (void *)skb); +} + +#endif /* _KUNIT_SKBUFF_H */
On Wed, 20 Dec 2023 at 23:20, benjamin@sipsolutions.net wrote:
From: Benjamin Berg benjamin.berg@intel.com
Add a simple convenience helper to allocate and zero fill an SKB for the use by a kunit test. Also provide a way to free it again in case that may be desirable.
This simply mirrors the kunit_kmalloc API.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com
I'm happy with this as-is, but do think there's a discussion to be had about where subsystem-specific KUnit helpers should live. I think, because this is just a header (and it mirrors the normal linux/skbuff.h), that having it in include/kunit works well.
If it needed a source file, I'm not 100% sure whether it should be in net/core/ or lib/kunit.
Regardless, this looks good to me, modulo the small nitpick below.
Reviewed-by: David Gow davidgow@google.com
include/kunit/skbuff.h | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 include/kunit/skbuff.h
diff --git a/include/kunit/skbuff.h b/include/kunit/skbuff.h new file mode 100644 index 000000000000..2144d01e556f --- /dev/null +++ b/include/kunit/skbuff.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Base unit test (KUnit) API.
This probably needs a better description which mentions skbuff, and that it's for resource management.
- Copyright (C) 2023 Intel Corporation
- */
+#ifndef _KUNIT_SKBUFF_H +#define _KUNIT_SKBUFF_H
+#include <kunit/resource.h> +#include <linux/skbuff.h>
+static void kunit_action_kfree_skb(void *p) +{
kfree_skb((struct sk_buff *)p);
+}
+/**
- kunit_zalloc_skb() - Allocate and initialize a resource managed skb.
- @test: The test case to which the skb belongs
- @len: size to allocate
- Allocate a new struct sk_buff with GFP_KERNEL, zero fill the give length
- and add it as a resource to the kunit test for automatic cleanup.
- Returns: newly allocated SKB, or %NULL on error
- */
+static inline struct sk_buff *kunit_zalloc_skb(struct kunit *test, int len,
gfp_t gfp)
+{
struct sk_buff *res = alloc_skb(len, GFP_KERNEL);
if (!res || skb_pad(res, len))
return NULL;
if (kunit_add_action_or_reset(test, kunit_action_kfree_skb, res))
return NULL;
return res;
+}
+/**
- kunit_kfree_skb() - Like kfree_skb except for allocations managed by KUnit.
- @test: The test case to which the resource belongs.
- @skb: The SKB to free.
- */
+static inline void kunit_kfree_skb(struct kunit *test, struct sk_buff *skb) +{
if (!skb)
return;
kunit_release_action(test, kunit_action_kfree_skb, (void *)skb);
+}
+#endif /* _KUNIT_SKBUFF_H */
2.43.0
-- You received this message because you are subscribed to the Google Groups "KUnit Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/20231220151952.415232-3-benjamin....
From: Johannes Berg johannes.berg@intel.com
Check the logic in ieee80211_drop_unencrypted_mgmt() according to a list of test cases derived from the spec.
Signed-off-by: Johannes Berg johannes.berg@intel.com Reviewed-by: Benjamin Berg benjamin.berg@intel.com --- net/mac80211/ieee80211_i.h | 10 ++ net/mac80211/rx.c | 4 +- net/mac80211/tests/Makefile | 2 +- net/mac80211/tests/mfp.c | 184 ++++++++++++++++++++++++++++++++++++ 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 net/mac80211/tests/mfp.c
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 29312f6638a1..71fafcd6a36e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2610,4 +2610,14 @@ void ieee80211_check_wbrf_support(struct ieee80211_local *local); void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef); void ieee80211_remove_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef);
+#if IS_ENABLED(CONFIG_MAC80211_KUNIT_TEST) +#define EXPORT_SYMBOL_IF_MAC80211_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym) +#define VISIBLE_IF_MAC80211_KUNIT +ieee80211_rx_result +ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx); +#else +#define EXPORT_SYMBOL_IF_MAC80211_KUNIT(sym) +#define VISIBLE_IF_MAC80211_KUNIT static +#endif + #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bbfdcb0ade72..d294787feed0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,6 +19,7 @@ #include <linux/export.h> #include <linux/kcov.h> #include <linux/bitops.h> +#include <kunit/visibility.h> #include <net/mac80211.h> #include <net/ieee80211_radiotap.h> #include <asm/unaligned.h> @@ -2405,7 +2406,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) return 0; }
-static ieee80211_rx_result +VISIBLE_IF_MAC80211_KUNIT ieee80211_rx_result ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); @@ -2484,6 +2485,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
return RX_CONTINUE; } +EXPORT_SYMBOL_IF_MAC80211_KUNIT(ieee80211_drop_unencrypted_mgmt);
static ieee80211_rx_result __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) diff --git a/net/mac80211/tests/Makefile b/net/mac80211/tests/Makefile index 4814584f8a14..4fdaf3feaca3 100644 --- a/net/mac80211/tests/Makefile +++ b/net/mac80211/tests/Makefile @@ -1,3 +1,3 @@ -mac80211-tests-y += module.o elems.o +mac80211-tests-y += module.o elems.o mfp.o
obj-$(CONFIG_MAC80211_KUNIT_TEST) += mac80211-tests.o diff --git a/net/mac80211/tests/mfp.c b/net/mac80211/tests/mfp.c new file mode 100644 index 000000000000..629a5801c08f --- /dev/null +++ b/net/mac80211/tests/mfp.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit tests for management frame acceptance + * + * Copyright (C) 2023 Intel Corporation + */ +#include <kunit/test.h> +#include <kunit/skbuff.h> +#include "../ieee80211_i.h" +#include "../sta_info.h" + +MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); + +static const struct mfp_test_case { + const char *desc; + bool sta, mfp, decrypted, unicast, protected_dual; + ieee80211_rx_result result; +} accept_public_action_cases[] = { + /* regular public action */ + { + .desc = "public action: accept unicast from unknown peer", + .unicast = true, + .result = RX_CONTINUE, + }, + { + .desc = "public action: accept multicast from unknown peer", + .unicast = false, + .result = RX_CONTINUE, + }, + { + .desc = "public action: accept unicast without MFP", + .unicast = true, + .sta = true, + .result = RX_CONTINUE, + }, + { + .desc = "public action: accept multicast without MFP", + .unicast = false, + .sta = true, + .result = RX_CONTINUE, + }, + { + .desc = "public action: drop unicast with MFP", + .unicast = true, + .sta = true, + .mfp = true, + .result = RX_DROP_U_UNPROT_UNICAST_PUB_ACTION, + }, + { + .desc = "public action: accept multicast with MFP", + .unicast = false, + .sta = true, + .mfp = true, + .result = RX_CONTINUE, + }, + /* protected dual of public action */ + { + .desc = "protected dual: drop unicast from unknown peer", + .protected_dual = true, + .unicast = true, + .result = RX_DROP_U_UNPROT_DUAL, + }, + { + .desc = "protected dual: drop multicast from unknown peer", + .protected_dual = true, + .unicast = false, + .result = RX_DROP_U_UNPROT_DUAL, + }, + { + .desc = "protected dual: drop unicast without MFP", + .protected_dual = true, + .unicast = true, + .sta = true, + .result = RX_DROP_U_UNPROT_DUAL, + }, + { + .desc = "protected dual: drop multicast without MFP", + .protected_dual = true, + .unicast = false, + .sta = true, + .result = RX_DROP_U_UNPROT_DUAL, + }, + { + .desc = "protected dual: drop undecrypted unicast with MFP", + .protected_dual = true, + .unicast = true, + .sta = true, + .mfp = true, + .result = RX_DROP_U_UNPROT_DUAL, + }, + { + .desc = "protected dual: drop undecrypted multicast with MFP", + .protected_dual = true, + .unicast = false, + .sta = true, + .mfp = true, + .result = RX_DROP_U_UNPROT_DUAL, + }, + { + .desc = "protected dual: accept unicast with MFP", + .protected_dual = true, + .decrypted = true, + .unicast = true, + .sta = true, + .mfp = true, + .result = RX_CONTINUE, + }, + { + .desc = "protected dual: accept multicast with MFP", + .protected_dual = true, + .decrypted = true, + .unicast = false, + .sta = true, + .mfp = true, + .result = RX_CONTINUE, + }, +}; + +KUNIT_ARRAY_PARAM_DESC(accept_public_action, + accept_public_action_cases, + desc); + +static void accept_public_action(struct kunit *test) +{ + static struct sta_info sta = {}; + const struct mfp_test_case *params = test->param_value; + struct ieee80211_rx_data rx = { + .sta = params->sta ? &sta : NULL, + }; + struct ieee80211_rx_status *status; + struct ieee80211_hdr_3addr hdr = { + .frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION), + .addr1 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + .addr2 = { 0x12, 0x22, 0x33, 0x44, 0x55, 0x66 }, + /* A3/BSSID doesn't matter here */ + }; + + if (!params->sta) { + KUNIT_ASSERT_FALSE(test, params->mfp); + KUNIT_ASSERT_FALSE(test, params->decrypted); + } + + if (params->mfp) + set_sta_flag(&sta, WLAN_STA_MFP); + + rx.skb = kunit_zalloc_skb(test, 128, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, rx.skb); + status = IEEE80211_SKB_RXCB(rx.skb); + + if (params->decrypted) { + status->flag |= RX_FLAG_DECRYPTED; + if (params->unicast) + hdr.frame_control |= + cpu_to_le16(IEEE80211_FCTL_PROTECTED); + } + + if (params->unicast) + hdr.addr1[0] = 0x02; + + skb_put_data(rx.skb, &hdr, sizeof(hdr)); + + if (params->protected_dual) + skb_put_u8(rx.skb, WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION); + else + skb_put_u8(rx.skb, WLAN_CATEGORY_PUBLIC); + skb_put_u8(rx.skb, WLAN_PUB_ACTION_DSE_ENABLEMENT); + + KUNIT_EXPECT_EQ(test, + ieee80211_drop_unencrypted_mgmt(&rx), + params->result); +} + +static struct kunit_case mfp_test_cases[] = { + KUNIT_CASE_PARAM(accept_public_action, accept_public_action_gen_params), + {} +}; + +static struct kunit_suite mfp = { + .name = "mac80211-mfp", + .test_cases = mfp_test_cases, +}; + +kunit_test_suite(mfp);
From: Johannes Berg johannes.berg@intel.com
Generalize the test to be able to handle arbitrary action categories and non-action frames, for further test expansion.
Signed-off-by: Johannes Berg johannes.berg@intel.com Reviewed-by: Gregory Greenman gregory.greenman@intel.com --- net/mac80211/tests/mfp.c | 78 +++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 21 deletions(-)
diff --git a/net/mac80211/tests/mfp.c b/net/mac80211/tests/mfp.c index 629a5801c08f..6ec31386c0df 100644 --- a/net/mac80211/tests/mfp.c +++ b/net/mac80211/tests/mfp.c @@ -13,34 +13,52 @@ MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
static const struct mfp_test_case { const char *desc; - bool sta, mfp, decrypted, unicast, protected_dual; + bool sta, mfp, decrypted, unicast; + u8 category; + u8 stype; + u8 action; ieee80211_rx_result result; -} accept_public_action_cases[] = { +} accept_mfp_cases[] = { /* regular public action */ { .desc = "public action: accept unicast from unknown peer", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PUBLIC, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = true, .result = RX_CONTINUE, }, { .desc = "public action: accept multicast from unknown peer", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PUBLIC, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = false, .result = RX_CONTINUE, }, { .desc = "public action: accept unicast without MFP", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PUBLIC, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = true, .sta = true, .result = RX_CONTINUE, }, { .desc = "public action: accept multicast without MFP", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PUBLIC, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = false, .sta = true, .result = RX_CONTINUE, }, { .desc = "public action: drop unicast with MFP", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PUBLIC, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = true, .sta = true, .mfp = true, @@ -48,6 +66,9 @@ static const struct mfp_test_case { }, { .desc = "public action: accept multicast with MFP", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PUBLIC, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = false, .sta = true, .mfp = true, @@ -56,33 +77,43 @@ static const struct mfp_test_case { /* protected dual of public action */ { .desc = "protected dual: drop unicast from unknown peer", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = true, .result = RX_DROP_U_UNPROT_DUAL, }, { .desc = "protected dual: drop multicast from unknown peer", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = false, .result = RX_DROP_U_UNPROT_DUAL, }, { .desc = "protected dual: drop unicast without MFP", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = true, .sta = true, .result = RX_DROP_U_UNPROT_DUAL, }, { .desc = "protected dual: drop multicast without MFP", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = false, .sta = true, .result = RX_DROP_U_UNPROT_DUAL, }, { .desc = "protected dual: drop undecrypted unicast with MFP", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = true, .sta = true, .mfp = true, @@ -90,7 +121,9 @@ static const struct mfp_test_case { }, { .desc = "protected dual: drop undecrypted multicast with MFP", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .unicast = false, .sta = true, .mfp = true, @@ -98,7 +131,9 @@ static const struct mfp_test_case { }, { .desc = "protected dual: accept unicast with MFP", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .decrypted = true, .unicast = true, .sta = true, @@ -107,7 +142,9 @@ static const struct mfp_test_case { }, { .desc = "protected dual: accept multicast with MFP", - .protected_dual = true, + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, + .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, .decrypted = true, .unicast = false, .sta = true, @@ -116,11 +153,9 @@ static const struct mfp_test_case { }, };
-KUNIT_ARRAY_PARAM_DESC(accept_public_action, - accept_public_action_cases, - desc); +KUNIT_ARRAY_PARAM_DESC(accept_mfp, accept_mfp_cases, desc);
-static void accept_public_action(struct kunit *test) +static void accept_mfp(struct kunit *test) { static struct sta_info sta = {}; const struct mfp_test_case *params = test->param_value; @@ -130,7 +165,7 @@ static void accept_public_action(struct kunit *test) struct ieee80211_rx_status *status; struct ieee80211_hdr_3addr hdr = { .frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ACTION), + params->stype), .addr1 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .addr2 = { 0x12, 0x22, 0x33, 0x44, 0x55, 0x66 }, /* A3/BSSID doesn't matter here */ @@ -160,11 +195,12 @@ static void accept_public_action(struct kunit *test)
skb_put_data(rx.skb, &hdr, sizeof(hdr));
- if (params->protected_dual) - skb_put_u8(rx.skb, WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION); - else - skb_put_u8(rx.skb, WLAN_CATEGORY_PUBLIC); - skb_put_u8(rx.skb, WLAN_PUB_ACTION_DSE_ENABLEMENT); + switch (params->stype) { + case IEEE80211_STYPE_ACTION: + skb_put_u8(rx.skb, params->category); + skb_put_u8(rx.skb, params->action); + break; + }
KUNIT_EXPECT_EQ(test, ieee80211_drop_unencrypted_mgmt(&rx), @@ -172,7 +208,7 @@ static void accept_public_action(struct kunit *test) }
static struct kunit_case mfp_test_cases[] = { - KUNIT_CASE_PARAM(accept_public_action, accept_public_action_gen_params), + KUNIT_CASE_PARAM(accept_mfp, accept_mfp_gen_params), {} };
From: Johannes Berg johannes.berg@intel.com
Extend the MFP tests to handle the case of deauth/disassoc and robust action frames (that are not protected dual of public action frames).
Signed-off-by: Johannes Berg johannes.berg@intel.com Reviewed-by: Gregory Greenman gregory.greenman@intel.com --- net/mac80211/tests/mfp.c | 74 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-)
diff --git a/net/mac80211/tests/mfp.c b/net/mac80211/tests/mfp.c index 6ec31386c0df..a8dc1601da60 100644 --- a/net/mac80211/tests/mfp.c +++ b/net/mac80211/tests/mfp.c @@ -13,7 +13,7 @@ MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
static const struct mfp_test_case { const char *desc; - bool sta, mfp, decrypted, unicast; + bool sta, mfp, decrypted, unicast, assoc; u8 category; u8 stype; u8 action; @@ -151,13 +151,67 @@ static const struct mfp_test_case { .mfp = true, .result = RX_CONTINUE, }, + /* deauth/disassoc before keys are set */ + { + .desc = "deauth: accept unicast with MFP but w/o key", + .stype = IEEE80211_STYPE_DEAUTH, + .sta = true, + .mfp = true, + .unicast = true, + .result = RX_CONTINUE, + }, + { + .desc = "disassoc: accept unicast with MFP but w/o key", + .stype = IEEE80211_STYPE_DEAUTH, + .sta = true, + .mfp = true, + .unicast = true, + .result = RX_CONTINUE, + }, + /* non-public robust action frame ... */ + { + .desc = "BA action: drop unicast before assoc", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_BACK, + .unicast = true, + .sta = true, + .result = RX_DROP_U_UNPROT_ROBUST_ACTION, + }, + { + .desc = "BA action: drop unprotected after assoc", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_BACK, + .unicast = true, + .sta = true, + .mfp = true, + .result = RX_DROP_U_UNPROT_UCAST_MGMT, + }, + { + .desc = "BA action: accept unprotected without MFP", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_BACK, + .unicast = true, + .sta = true, + .assoc = true, + .mfp = false, + .result = RX_CONTINUE, + }, + { + .desc = "BA action: drop unprotected with MFP", + .stype = IEEE80211_STYPE_ACTION, + .category = WLAN_CATEGORY_BACK, + .unicast = true, + .sta = true, + .mfp = true, + .result = RX_DROP_U_UNPROT_UCAST_MGMT, + }, };
KUNIT_ARRAY_PARAM_DESC(accept_mfp, accept_mfp_cases, desc);
static void accept_mfp(struct kunit *test) { - static struct sta_info sta = {}; + static struct sta_info sta; const struct mfp_test_case *params = test->param_value; struct ieee80211_rx_data rx = { .sta = params->sta ? &sta : NULL, @@ -171,6 +225,8 @@ static void accept_mfp(struct kunit *test) /* A3/BSSID doesn't matter here */ };
+ memset(&sta, 0, sizeof(sta)); + if (!params->sta) { KUNIT_ASSERT_FALSE(test, params->mfp); KUNIT_ASSERT_FALSE(test, params->decrypted); @@ -179,6 +235,9 @@ static void accept_mfp(struct kunit *test) if (params->mfp) set_sta_flag(&sta, WLAN_STA_MFP);
+ if (params->assoc) + set_bit(WLAN_STA_ASSOC, &sta._flags); + rx.skb = kunit_zalloc_skb(test, 128, GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, rx.skb); status = IEEE80211_SKB_RXCB(rx.skb); @@ -200,11 +259,18 @@ static void accept_mfp(struct kunit *test) skb_put_u8(rx.skb, params->category); skb_put_u8(rx.skb, params->action); break; + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_DISASSOC: { + __le16 reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); + + skb_put_data(rx.skb, &reason, sizeof(reason)); + } + break; }
KUNIT_EXPECT_EQ(test, - ieee80211_drop_unencrypted_mgmt(&rx), - params->result); + (__force u32)ieee80211_drop_unencrypted_mgmt(&rx), + (__force u32)params->result); }
static struct kunit_case mfp_test_cases[] = {
From: Benjamin Berg benjamin.berg@intel.com
This adds some scanning related tests, mainly exercising the ML element parsing and inheritance.
Signed-off-by: Benjamin Berg benjamin.berg@intel.com Reviewed-by: Johannes Berg johannes.berg@intel.com --- net/wireless/core.h | 13 +- net/wireless/scan.c | 9 +- net/wireless/tests/Makefile | 2 +- net/wireless/tests/scan.c | 625 ++++++++++++++++++++++++++++++++++++ net/wireless/tests/util.c | 56 ++++ net/wireless/tests/util.h | 66 ++++ 6 files changed, 766 insertions(+), 5 deletions(-) create mode 100644 net/wireless/tests/scan.c create mode 100644 net/wireless/tests/util.c create mode 100644 net/wireless/tests/util.h
diff --git a/net/wireless/core.h b/net/wireless/core.h index 1963958263d2..13657a85cf61 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -3,7 +3,7 @@ * Wireless configuration interface internals. * * Copyright 2006-2010 Johannes Berg johannes@sipsolutions.net - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #ifndef __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H @@ -549,4 +549,15 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask);
+#if IS_ENABLED(CONFIG_CFG80211_KUNIT_TEST) +#define EXPORT_SYMBOL_IF_CFG80211_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym) +#define VISIBLE_IF_CFG80211_KUNIT +size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, + const u8 *subie, size_t subie_len, + u8 *new_ie, size_t new_ie_len); +#else +#define EXPORT_SYMBOL_IF_CFG80211_KUNIT(sym) +#define VISIBLE_IF_CFG80211_KUNIT static +#endif /* IS_ENABLED(CONFIG_CFG80211_KUNIT_TEST) */ + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 3d260c99c348..f6c0421f4d77 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -20,6 +20,7 @@ #include <net/cfg80211.h> #include <net/cfg80211-wext.h> #include <net/iw_handler.h> +#include <kunit/visibility.h> #include "core.h" #include "nl80211.h" #include "wext-compat.h" @@ -303,9 +304,10 @@ static size_t cfg80211_copy_elem_with_frags(const struct element *elem, return *pos - buf; }
-static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, - const u8 *subie, size_t subie_len, - u8 *new_ie, size_t new_ie_len) +VISIBLE_IF_CFG80211_KUNIT size_t +cfg80211_gen_new_ie(const u8 *ie, size_t ielen, + const u8 *subie, size_t subie_len, + u8 *new_ie, size_t new_ie_len) { const struct element *non_inherit_elem, *parent, *sub; u8 *pos = new_ie; @@ -413,6 +415,7 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
return pos - new_ie; } +EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_gen_new_ie);
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, const u8 *ssid, size_t ssid_len) diff --git a/net/wireless/tests/Makefile b/net/wireless/tests/Makefile index fa8e297bbc5e..1f6622fcb758 100644 --- a/net/wireless/tests/Makefile +++ b/net/wireless/tests/Makefile @@ -1,3 +1,3 @@ -cfg80211-tests-y += module.o fragmentation.o +cfg80211-tests-y += module.o fragmentation.o scan.o util.o
obj-$(CONFIG_CFG80211_KUNIT_TEST) += cfg80211-tests.o diff --git a/net/wireless/tests/scan.c b/net/wireless/tests/scan.c new file mode 100644 index 000000000000..77854161cd22 --- /dev/null +++ b/net/wireless/tests/scan.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit tests for inform_bss functions + * + * Copyright (C) 2023 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 struct inform_bss_ml_sta_case { + const char *desc; + int mld_id; + bool sta_prof_vendor_elems; +} inform_bss_ml_sta_cases[] = { + { .desc = "no_mld_id", .mld_id = 0, .sta_prof_vendor_elems = false }, + { .desc = "mld_id_eq_1", .mld_id = 1, .sta_prof_vendor_elems = true }, +}; +KUNIT_ARRAY_PARAM_DESC(inform_bss_ml_sta, inform_bss_ml_sta_cases, desc) + +static void test_inform_bss_ml_sta(struct kunit *test) +{ + const struct inform_bss_ml_sta_case *params = test->param_value; + 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, + }; + struct cfg80211_bss *bss, *link_bss; + const struct cfg80211_bss_ies *ies; + + /* sending station */ + const u8 bssid[ETH_ALEN] = { 0x10, 0x22, 0x33, 0x44, 0x55, 0x66 }; + u64 tsf = 0x1000000000000000ULL; + int beacon_int = 100; + u16 capability = 0x1234; + + /* Building the frame *************************************************/ + struct sk_buff *input = kunit_zalloc_skb(test, 1024, GFP_KERNEL); + u8 *len_mle, *len_prof; + u8 link_id = 2; + struct { + struct ieee80211_neighbor_ap_info info; + struct ieee80211_tbtt_info_ge_11 ap; + } __packed rnr = { + .info = { + .tbtt_info_hdr = u8_encode_bits(0, IEEE80211_AP_INFO_TBTT_HDR_COUNT), + .tbtt_info_len = sizeof(struct ieee80211_tbtt_info_ge_11), + .op_class = 81, + .channel = 11, + }, + .ap = { + .tbtt_offset = 0xff, + .bssid = { 0x10, 0x22, 0x33, 0x44, 0x55, 0x67 }, + .short_ssid = 0, /* unused */ + .bss_params = 0, + .psd_20 = 0, + .mld_params.mld_id = params->mld_id, + .mld_params.params = + le16_encode_bits(link_id, + IEEE80211_RNR_MLD_PARAMS_LINK_ID), + } + }; + struct { + __le16 control; + u8 var_len; + u8 mld_mac_addr[ETH_ALEN]; + u8 link_id_info; + u8 params_change_count; + __le16 mld_caps_and_ops; + u8 mld_id; + __le16 ext_mld_caps_and_ops; + } __packed mle_basic_common_info = { + .control = + cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC | + IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT | + IEEE80211_MLC_BASIC_PRES_LINK_ID | + (params->mld_id ? IEEE80211_MLC_BASIC_PRES_MLD_ID : 0) | + IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP), + .mld_id = params->mld_id, + .mld_caps_and_ops = cpu_to_le16(0x0102), + .ext_mld_caps_and_ops = cpu_to_le16(0x0304), + .var_len = sizeof(mle_basic_common_info) - 2 - + (params->mld_id ? 0 : 1), + .mld_mac_addr = { 0x10, 0x22, 0x33, 0x44, 0x55, 0x60 }, + }; + struct { + __le16 control; + u8 var_len; + u8 bssid[ETH_ALEN]; + __le16 beacon_int; + __le64 tsf_offset; + __le16 capabilities; /* already part of payload */ + } __packed sta_prof = { + .control = + cpu_to_le16(IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE | + IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT | + IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT | + IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT | + u16_encode_bits(link_id, + IEEE80211_MLE_STA_CONTROL_LINK_ID)), + .var_len = sizeof(sta_prof) - 2 - 2, + .bssid = { *rnr.ap.bssid }, + .beacon_int = cpu_to_le16(101), + .tsf_offset = cpu_to_le64(-123ll), + .capabilities = cpu_to_le16(0xdead), + }; + + KUNIT_ASSERT_NOT_NULL(test, input); + + 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); + + skb_put_u8(input, WLAN_EID_SSID); + skb_put_u8(input, 4); + skb_put_data(input, "TEST", 4); + + skb_put_u8(input, WLAN_EID_REDUCED_NEIGHBOR_REPORT); + skb_put_u8(input, sizeof(rnr)); + skb_put_data(input, &rnr, sizeof(rnr)); + + /* build a multi-link element */ + skb_put_u8(input, WLAN_EID_EXTENSION); + len_mle = skb_put(input, 1); + skb_put_u8(input, WLAN_EID_EXT_EHT_MULTI_LINK); + skb_put_data(input, &mle_basic_common_info, sizeof(mle_basic_common_info)); + if (!params->mld_id) + t_skb_remove_member(input, typeof(mle_basic_common_info), mld_id); + /* with a STA profile inside */ + skb_put_u8(input, IEEE80211_MLE_SUBELEM_PER_STA_PROFILE); + len_prof = skb_put(input, 1); + skb_put_data(input, &sta_prof, sizeof(sta_prof)); + + if (params->sta_prof_vendor_elems) { + /* Put two (vendor) element into sta_prof */ + skb_put_u8(input, WLAN_EID_VENDOR_SPECIFIC); + skb_put_u8(input, 160); + skb_put(input, 160); + + skb_put_u8(input, WLAN_EID_VENDOR_SPECIFIC); + skb_put_u8(input, 165); + skb_put(input, 165); + } + + /* fragment STA profile */ + ieee80211_fragment_element(input, len_prof, + IEEE80211_MLE_SUBELEM_FRAGMENT); + /* fragment MLE */ + ieee80211_fragment_element(input, len_mle, WLAN_EID_FRAGMENT); + + /* Put a (vendor) element after the ML element */ + skb_put_u8(input, WLAN_EID_VENDOR_SPECIFIC); + skb_put_u8(input, 155); + skb_put(input, 155); + + /* Submit *************************************************************/ + bss = cfg80211_inform_bss_data(wiphy, &inform_bss, + CFG80211_BSS_FTYPE_PRESP, bssid, tsf, + capability, beacon_int, + input->data, input->len, + GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, bss); + KUNIT_EXPECT_EQ(test, ctx.inform_bss_count, 2); + + /* Check link_bss *****************************************************/ + link_bss = cfg80211_get_bss(wiphy, NULL, sta_prof.bssid, NULL, 0, + IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY_ANY); + KUNIT_ASSERT_NOT_NULL(test, link_bss); + KUNIT_EXPECT_EQ(test, link_bss->signal, 0); + KUNIT_EXPECT_EQ(test, link_bss->beacon_interval, + le16_to_cpu(sta_prof.beacon_int)); + KUNIT_EXPECT_EQ(test, link_bss->capability, + le16_to_cpu(sta_prof.capabilities)); + KUNIT_EXPECT_EQ(test, link_bss->bssid_index, 0); + KUNIT_EXPECT_PTR_EQ(test, link_bss->channel, + ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(2462))); + + rcu_read_lock(); + ies = rcu_dereference(link_bss->ies); + KUNIT_EXPECT_NOT_NULL(test, ies); + KUNIT_EXPECT_EQ(test, ies->tsf, tsf + le64_to_cpu(sta_prof.tsf_offset)); + /* Resulting length should be: + * SSID (inherited) + RNR (inherited) + vendor element(s) + + * MLE common info + MLE header and control + */ + if (params->sta_prof_vendor_elems) + KUNIT_EXPECT_EQ(test, ies->len, + 6 + 2 + sizeof(rnr) + 2 + 160 + 2 + 165 + + mle_basic_common_info.var_len + 5); + else + KUNIT_EXPECT_EQ(test, ies->len, + 6 + 2 + sizeof(rnr) + 2 + 155 + + mle_basic_common_info.var_len + 5); + rcu_read_unlock(); + + cfg80211_put_bss(wiphy, bss); + cfg80211_put_bss(wiphy, link_bss); +} + +static struct kunit_case gen_new_ie_test_cases[] = { + KUNIT_CASE_PARAM(test_gen_new_ie, gen_new_ie_gen_params), + KUNIT_CASE(test_gen_new_ie_malformed), + {} +}; + +static struct kunit_suite gen_new_ie = { + .name = "cfg80211-ie-generation", + .test_cases = gen_new_ie_test_cases, +}; + +kunit_test_suite(gen_new_ie); + +static struct kunit_case inform_bss_test_cases[] = { + KUNIT_CASE(test_inform_bss_ssid_only), + KUNIT_CASE_PARAM(test_inform_bss_ml_sta, inform_bss_ml_sta_gen_params), + {} +}; + +static struct kunit_suite inform_bss = { + .name = "cfg80211-inform-bss", + .test_cases = inform_bss_test_cases, +}; + +kunit_test_suite(inform_bss); diff --git a/net/wireless/tests/util.c b/net/wireless/tests/util.c new file mode 100644 index 000000000000..8abdaeb820ce --- /dev/null +++ b/net/wireless/tests/util.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit fixture to have a (configurable) wiphy + * + * Copyright (C) 2023 Intel Corporation + */ +#include <linux/ieee80211.h> +#include <net/cfg80211.h> +#include <kunit/test.h> +#include <kunit/test-bug.h> +#include "util.h" + +int t_wiphy_init(struct kunit_resource *resource, void *ctx) +{ + struct kunit *test = kunit_get_current_test(); + struct cfg80211_ops *ops; + struct wiphy *wiphy; + struct t_wiphy_priv *priv; + + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ops); + + wiphy = wiphy_new_nm(ops, sizeof(*priv), "kunit"); + KUNIT_ASSERT_NOT_NULL(test, wiphy); + + priv = wiphy_priv(wiphy); + priv->ctx = ctx; + priv->ops = ops; + + /* Initialize channels, feel free to add more here channels/bands */ + memcpy(priv->channels_2ghz, channels_2ghz, sizeof(channels_2ghz)); + wiphy->bands[NL80211_BAND_2GHZ] = &priv->band_2ghz; + priv->band_2ghz.channels = priv->channels_2ghz; + priv->band_2ghz.n_channels = ARRAY_SIZE(channels_2ghz); + + resource->data = wiphy; + resource->name = "wiphy"; + + return 0; +} + +void t_wiphy_exit(struct kunit_resource *resource) +{ + struct t_wiphy_priv *priv; + struct cfg80211_ops *ops; + + priv = wiphy_priv(resource->data); + ops = priv->ops; + + /* Should we ensure anything about the state here? + * e.g. full destruction or no calls to any ops on destruction? + */ + + wiphy_free(resource->data); + kfree(ops); +} diff --git a/net/wireless/tests/util.h b/net/wireless/tests/util.h new file mode 100644 index 000000000000..6de712e0d432 --- /dev/null +++ b/net/wireless/tests/util.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Utilities for cfg80211 unit testing + * + * Copyright (C) 2023 Intel Corporation + */ +#ifndef __CFG80211_UTILS_H +#define __CFG80211_UTILS_H + +#define CHAN2G(_freq) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_freq), \ +} + +static const struct ieee80211_channel channels_2ghz[] = { + CHAN2G(2412), /* Channel 1 */ + CHAN2G(2417), /* Channel 2 */ + CHAN2G(2422), /* Channel 3 */ + CHAN2G(2427), /* Channel 4 */ + CHAN2G(2432), /* Channel 5 */ + CHAN2G(2437), /* Channel 6 */ + CHAN2G(2442), /* Channel 7 */ + CHAN2G(2447), /* Channel 8 */ + CHAN2G(2452), /* Channel 9 */ + CHAN2G(2457), /* Channel 10 */ + CHAN2G(2462), /* Channel 11 */ + CHAN2G(2467), /* Channel 12 */ + CHAN2G(2472), /* Channel 13 */ + CHAN2G(2484), /* Channel 14 */ +}; + +struct t_wiphy_priv { + struct kunit *test; + struct cfg80211_ops *ops; + + void *ctx; + + struct ieee80211_supported_band band_2ghz; + struct ieee80211_channel channels_2ghz[ARRAY_SIZE(channels_2ghz)]; +}; + +#define T_WIPHY(test, ctx) ({ \ + struct wiphy *__wiphy = \ + kunit_alloc_resource(test, t_wiphy_init, \ + t_wiphy_exit, \ + GFP_KERNEL, &(ctx)); \ + \ + KUNIT_ASSERT_NOT_NULL(test, __wiphy); \ + __wiphy; \ + }) +#define t_wiphy_ctx(wiphy) (((struct t_wiphy_priv *)wiphy_priv(wiphy))->ctx) + +int t_wiphy_init(struct kunit_resource *resource, void *data); +void t_wiphy_exit(struct kunit_resource *resource); + +#define t_skb_remove_member(skb, type, member) do { \ + memmove((skb)->data + (skb)->len - sizeof(type) + \ + offsetof(type, member), \ + (skb)->data + (skb)->len - sizeof(type) + \ + offsetofend(type, member), \ + offsetofend(type, member)); \ + skb_trim(skb, (skb)->len - sizeof_field(type, member)); \ + } while (0) + +#endif /* __CFG80211_UTILS_H */
This patchset adds a couple of helpers for kunit as well as tests for cfg80211 and mac80211 that use them.
I can take this through the wireless tree, but then I'd like to have ACKs from kunit folks for the kunit patches:
kunit: add parameter generation macro using description from array kunit: add a convenience allocation wrapper for SKBs
Thanks, johannes
On 12/21/23 12:39, Johannes Berg wrote:
This patchset adds a couple of helpers for kunit as well as tests for cfg80211 and mac80211 that use them.
I can take this through the wireless tree, but then I'd like to have ACKs from kunit folks for the kunit patches:
We have run into conflicts in the past with the kunit tree. I take the kunit patches through linux-kselftest tree. I do want to make sure there are no conflicts. I don't mind taking these through my tree.
kunit: add parameter generation macro using description from array kunit: add a convenience allocation wrapper for SKBs
Adding David and Brendan to the thread for their review.
thanks, -- Shuah
On Thu, 2023-12-21 at 13:06 -0700, Shuah Khan wrote:
On 12/21/23 12:39, Johannes Berg wrote:
This patchset adds a couple of helpers for kunit as well as tests for cfg80211 and mac80211 that use them.
I can take this through the wireless tree, but then I'd like to have ACKs from kunit folks for the kunit patches:
We have run into conflicts in the past with the kunit tree. I take the kunit patches through linux-kselftest tree. I do want to make sure there are no conflicts. I don't mind taking these through my tree.
OK, fair enough.
If you can still put it into 6.8, then I think you can also take the wireless tests, assuming they pass (I haven't run them in the posted version). I don't think we'll have conflicts there, we don't have much work in wireless that's likely to land for 6.8.
johannes
On 12/21/23 13:40, Johannes Berg wrote:
On Thu, 2023-12-21 at 13:06 -0700, Shuah Khan wrote:
On 12/21/23 12:39, Johannes Berg wrote:
This patchset adds a couple of helpers for kunit as well as tests for cfg80211 and mac80211 that use them.
I can take this through the wireless tree, but then I'd like to have ACKs from kunit folks for the kunit patches:
We have run into conflicts in the past with the kunit tree. I take the kunit patches through linux-kselftest tree. I do want to make sure there are no conflicts. I don't mind taking these through my tree.
OK, fair enough.
If you can still put it into 6.8, then I think you can also take the wireless tests, assuming they pass (I haven't run them in the posted version). I don't think we'll have conflicts there, we don't have much work in wireless that's likely to land for 6.8.
Sounds good.
David, will you be able to look at these patches and let me know if I can apply for Linux 6.8-rc1.
thanks, -- Shuah
On Fri, 22 Dec 2023 at 05:47, Shuah Khan skhan@linuxfoundation.org wrote:
On 12/21/23 13:40, Johannes Berg wrote:
On Thu, 2023-12-21 at 13:06 -0700, Shuah Khan wrote:
On 12/21/23 12:39, Johannes Berg wrote:
This patchset adds a couple of helpers for kunit as well as tests for cfg80211 and mac80211 that use them.
I can take this through the wireless tree, but then I'd like to have ACKs from kunit folks for the kunit patches:
We have run into conflicts in the past with the kunit tree. I take the kunit patches through linux-kselftest tree. I do want to make sure there are no conflicts. I don't mind taking these through my tree.
OK, fair enough.
If you can still put it into 6.8, then I think you can also take the wireless tests, assuming they pass (I haven't run them in the posted version). I don't think we'll have conflicts there, we don't have much work in wireless that's likely to land for 6.8.
Sounds good.
David, will you be able to look at these patches and let me know if I can apply for Linux 6.8-rc1.
The two initial KUnit patches look fine, modulo a couple of minor docs issues and checkpatch warnings. They apply cleanly, and I doubt there's much chance of there being a merge conflict for 6.8 -- there are no other changes to the parameterised test macros, and the skb stuff is in its own file.
The remaining patches don't apply on top of the kunit branch as-is. I haven't had a chance to review them properly yet; the initial glance I had didn't show any serious issues (though I think checkpatch suggested some things to 'check').
So (once those small issues are finished), I'm okay with the first two patches going in via either tree. The remaining ones are probably best done via the wireless tree, as they seem to depend on some existing patches there, so maybe it makes sense to push everything via wireless.
Cheers, -- David
Hi,
Thanks for taking a look!
On Fri, 2023-12-22 at 18:02 +0800, David Gow wrote:
The two initial KUnit patches look fine, modulo a couple of minor docs issues and checkpatch warnings.
I can run checkpatch (even if I can't always take it seriously), but do you want to comment more specifically wrt. the docs?
They apply cleanly, and I doubt there's much chance of there being a merge conflict for 6.8 -- there are no other changes to the parameterised test macros, and the skb stuff is in its own file.
Right.
The remaining patches don't apply on top of the kunit branch as-is.
Oh, OK. That makes some sense though, we've had a number of changes in the stack this cycle before. I somehow thought the tests were likely standalone, but apparently not.
I haven't had a chance to review them properly yet; the initial glance I had didn't show any serious issues (though I think checkpatch suggested some things to 'check').
I can check.
So (once those small issues are finished), I'm okay with the first two patches going in via either tree. The remaining ones are probably best done via the wireless tree, as they seem to depend on some existing patches there, so maybe it makes sense to push everything via wireless.
If not through wireless I doubt we'll get it synchronized for 6.8, though of course it's also not needed for 6.8 to have the extra unit tests :)
I'll let Shuah decide.
Thanks!
johannes
On Fri, 22 Dec 2023 at 18:09, Johannes Berg johannes@sipsolutions.net wrote:
Hi,
Thanks for taking a look!
On Fri, 2023-12-22 at 18:02 +0800, David Gow wrote:
The two initial KUnit patches look fine, modulo a couple of minor docs issues and checkpatch warnings.
I can run checkpatch (even if I can't always take it seriously), but do you want to comment more specifically wrt. the docs?
Sorry, the 'docs' issue was just the initial comment on the include/linux/skbuff.h file in patch 2, which could have been more specific to skbuff and resource management. The actual kerneldoc comments seem fine to me.
They apply cleanly, and I doubt there's much chance of there being a merge conflict for 6.8 -- there are no other changes to the parameterised test macros, and the skb stuff is in its own file.
Right.
The remaining patches don't apply on top of the kunit branch as-is.
Oh, OK. That makes some sense though, we've had a number of changes in the stack this cycle before. I somehow thought the tests were likely standalone, but apparently not.
I managed to get this to apply locally. The only real changes are to net/mac80211/ieee80211_i.h so it may be possible to port this across to the kselftest/kunit branch if you want, but it doesn't apply cleanly as-is.
Also, there are a couple of cfg80211 failures: --- KTAP version 1 1..1 KTAP version 1 # Subtest: cfg80211-inform-bss # module: cfg80211_tests 1..2 platform regulatory.0: Direct firmware load for regulatory.db failed with error -2 cfg80211: failed to load regulatory.db ok 1 test_inform_bss_ssid_only KTAP version 1 # Subtest: test_inform_bss_ml_sta # test_inform_bss_ml_sta: EXPECTATION FAILED at net/wireless/tests/scan.c:592 Expected ies->len == 6 + 2 + sizeof(rnr) + 2 + 155 + mle_basic_common_info.var_len + 5, but ies->len == 185 (0xb9) 6 + 2 + sizeof(rnr) + 2 + 155 + mle_basic_common_info.var_len + 5 == 203 (0xcb) not ok 1 no_mld_id # test_inform_bss_ml_sta: EXPECTATION FAILED at net/wireless/tests/scan.c:588 Expected ies->len == 6 + 2 + sizeof(rnr) + 2 + 160 + 2 + 165 + mle_basic_common_info.var_len + 5, but ies->len == 357 (0x165) 6 + 2 + sizeof(rnr) + 2 + 160 + 2 + 165 + mle_basic_common_info.var_len + 5 == 376 (0x178) not ok 2 mld_id_eq_1 # test_inform_bss_ml_sta: pass:0 fail:2 skip:0 total:2 not ok 2 test_inform_bss_ml_sta # cfg80211-inform-bss: pass:1 fail:1 skip:0 total:2 # Totals: pass:1 fail:2 skip:0 total:3 not ok 1 cfg80211-inform-bss ---
If the failures are because of the missing 'regulatory.db' file, would it make more sense to have that SKIP the tests instead? (And, if you actually want to check that it loads correctly, have that be its own, separate test?)
I haven't had a chance to review them properly yet; the initial glance I had didn't show any serious issues (though I think checkpatch suggested some things to 'check').
I can check.
Yeah, it mostly looks like really minor style 'suggestions' around indenting and putting blank lines in, along with a couple of "you're reusing a value in a macro, double check this" ones.. I'll paste them below (but warning, they're a bit verbose).
CHECK: Please use a blank line after function/struct/union/enum declarations #1142: FILE: net/wireless/tests/scan.c:225: +}; +KUNIT_ARRAY_PARAM_DESC(gen_new_ie, gen_new_ie_cases, desc)
CHECK: Please use a blank line after function/struct/union/enum declarations #1330: FILE: net/wireless/tests/scan.c:413: +}; +KUNIT_ARRAY_PARAM_DESC(inform_bss_ml_sta, inform_bss_ml_sta_cases, desc)
CHECK: Alignment should match open parenthesis #1489: FILE: net/wireless/tests/scan.c:572: + KUNIT_EXPECT_EQ(test, link_bss->beacon_interval, + le16_to_cpu(sta_prof.beacon_int));
CHECK: Alignment should match open parenthesis #1491: FILE: net/wireless/tests/scan.c:574: + KUNIT_EXPECT_EQ(test, link_bss->capability, + le16_to_cpu(sta_prof.capabilities));
CHECK: Macro argument reuse '_freq' - possible side-effects? #1620: FILE: net/wireless/tests/util.h:10: +#define CHAN2G(_freq) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_freq), \ +}
CHECK: Macro argument reuse 'test' - possible side-effects? #1653: FILE: net/wireless/tests/util.h:43: +#define T_WIPHY(test, ctx) ({ \ + struct wiphy *__wiphy = \ + kunit_alloc_resource(test, t_wiphy_init, \ + t_wiphy_exit, \ + GFP_KERNEL, &(ctx)); \ + \ + KUNIT_ASSERT_NOT_NULL(test, __wiphy); \ + __wiphy; \ + })
So (once those small issues are finished), I'm okay with the first two patches going in via either tree. The remaining ones are probably best done via the wireless tree, as they seem to depend on some existing patches there, so maybe it makes sense to push everything via wireless.
If not through wireless I doubt we'll get it synchronized for 6.8, though of course it's also not needed for 6.8 to have the extra unit tests :)
I'll let Shuah decide.
I think you should be able to rebase on top of the kunit tree if Shuah prefers that -- it's a reasonably straightforward conflict. But I think we'd want to make sure that the various issues above are fixed (and I'd not want the tests to fail out-of-the-box on the kunit.py UML setup, though having them depend on !UML or 'SKIP' should be fine).
Cheers, -- David
On 12/22/23 03:09, Johannes Berg wrote:
Hi,
Thanks for taking a look!
On Fri, 2023-12-22 at 18:02 +0800, David Gow wrote:
The two initial KUnit patches look fine, modulo a couple of minor docs issues and checkpatch warnings.
I can run checkpatch (even if I can't always take it seriously), but do you want to comment more specifically wrt. the docs?
They apply cleanly, and I doubt there's much chance of there being a merge conflict for 6.8 -- there are no other changes to the parameterised test macros, and the skb stuff is in its own file.
Right.
The remaining patches don't apply on top of the kunit branch as-is.
Oh, OK. That makes some sense though, we've had a number of changes in the stack this cycle before. I somehow thought the tests were likely standalone, but apparently not.
I haven't had a chance to review them properly yet; the initial glance I had didn't show any serious issues (though I think checkpatch suggested some things to 'check').
I can check.
So (once those small issues are finished), I'm okay with the first two patches going in via either tree. The remaining ones are probably best done via the wireless tree, as they seem to depend on some existing patches there, so maybe it makes sense to push everything via wireless.
If not through wireless I doubt we'll get it synchronized for 6.8, though of course it's also not needed for 6.8 to have the extra unit tests :)
I'll let Shuah decide.
Thank you David for the reviews.
johannes, Please take these through wireless - makes it easier for all of us.
Acked-by: Shuah Khan skhan@linuxfoundation.org
thanks, -- Shuah
linux-kselftest-mirror@lists.linaro.org