Commit a180b0b1 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'wireless-next-2024-01-03' of...

Merge tag 'wireless-next-2024-01-03' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
Just a couple of more things over the holidays:

 - first kunit tests for both cfg80211 and mac80211
 - a few multi-link fixes
 - DSCP mapping update
 - RCU fix

* tag 'wireless-next-2024-01-03' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next:
  wifi: mac80211: remove redundant ML element check
  wifi: cfg80211: parse all ML elements in an ML probe response
  wifi: cfg80211: correct comment about MLD ID
  wifi: cfg80211: Update the default DSCP-to-UP mapping
  wifi: cfg80211: tests: add some scanning related tests
  wifi: mac80211: kunit: extend MFP tests
  wifi: mac80211: kunit: generalize public action test
  wifi: mac80211: add kunit tests for public action handling
  kunit: add a convenience allocation wrapper for SKBs
  kunit: add parameter generation macro using description from array
  wifi: mac80211: fix spelling typo in comment
  wifi: cfg80211: fix RCU dereference in __cfg80211_bss_update
====================

Link: https://lore.kernel.org/r/20240103144423.52269-3-johannes@sipsolutions.netSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a2634a5f 3aca362a
...@@ -566,13 +566,9 @@ By reusing the same ``cases`` array from above, we can write the test as a ...@@ -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. // Creates `sha1_gen_params()` to iterate over `cases` while using
static void case_to_desc(const struct sha1_test_case *t, char *desc) // the struct member `str` for the case description.
{ KUNIT_ARRAY_PARAM_DESC(sha1, cases, str);
strcpy(desc, t->str);
}
// Creates `sha1_gen_params()` to iterate over `cases`.
KUNIT_ARRAY_PARAM(sha1, cases, case_to_desc);
// Looks no different from a normal test. // Looks no different from a normal test.
static void sha1_test(struct kunit *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 ...@@ -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 // 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[] = { static struct kunit_case sha1_test_cases[] = {
KUNIT_CASE_PARAM(sha1_test, sha1_gen_params), KUNIT_CASE_PARAM(sha1_test, sha1_gen_params),
{} {}
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* KUnit resource management helpers for SKBs (skbuff).
*
* 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 */
...@@ -1514,6 +1514,25 @@ do { \ ...@@ -1514,6 +1514,25 @@ do { \
return NULL; \ 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 // TODO(dlatypov@google.com): consider eventually migrating users to explicitly
// include resource.h themselves if they need it. // include resource.h themselves if they need it.
#include <kunit/resource.h> #include <kunit/resource.h>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "sta_info.h" #include "sta_info.h"
#include "driver-ops.h" #include "driver-ops.h"
/* sta attributtes */ /* sta attributes */
#define STA_READ(name, field, format_string) \ #define STA_READ(name, field, format_string) \
static ssize_t sta_ ##name## _read(struct file *file, \ static ssize_t sta_ ##name## _read(struct file *file, \
......
...@@ -2608,4 +2608,14 @@ void ieee80211_check_wbrf_support(struct ieee80211_local *local); ...@@ -2608,4 +2608,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_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef);
void ieee80211_remove_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 */ #endif /* IEEE80211_I_H */
...@@ -5407,23 +5407,15 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ...@@ -5407,23 +5407,15 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
} }
if (ieee80211_vif_is_mld(&sdata->vif)) { if (ieee80211_vif_is_mld(&sdata->vif)) {
struct ieee80211_mle_basic_common_info *common;
if (!elems->ml_basic) { if (!elems->ml_basic) {
sdata_info(sdata, sdata_info(sdata,
"MLO association with %pM but no multi-link element in response!\n", "MLO association with %pM but no (basic) multi-link element in response!\n",
assoc_data->ap_addr); assoc_data->ap_addr);
goto abandon_assoc; goto abandon_assoc;
} }
if (le16_get_bits(elems->ml_basic->control,
IEEE80211_ML_CONTROL_TYPE) !=
IEEE80211_ML_CONTROL_TYPE_BASIC) {
sdata_info(sdata,
"bad multi-link element (control=0x%x)\n",
le16_to_cpu(elems->ml_basic->control));
goto abandon_assoc;
} else {
struct ieee80211_mle_basic_common_info *common;
common = (void *)elems->ml_basic->variable; common = (void *)elems->ml_basic->variable;
if (memcmp(assoc_data->ap_addr, if (memcmp(assoc_data->ap_addr,
...@@ -5435,7 +5427,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ...@@ -5435,7 +5427,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
goto abandon_assoc; goto abandon_assoc;
} }
} }
}
sdata->vif.cfg.aid = aid; sdata->vif.cfg.aid = aid;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/kcov.h> #include <linux/kcov.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <kunit/visibility.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include <net/ieee80211_radiotap.h> #include <net/ieee80211_radiotap.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -2414,7 +2415,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) ...@@ -2414,7 +2415,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
return 0; return 0;
} }
static ieee80211_rx_result VISIBLE_IF_MAC80211_KUNIT ieee80211_rx_result
ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
{ {
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
...@@ -2493,6 +2494,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) ...@@ -2493,6 +2494,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
return RX_CONTINUE; return RX_CONTINUE;
} }
EXPORT_SYMBOL_IF_MAC80211_KUNIT(ieee80211_drop_unencrypted_mgmt);
static ieee80211_rx_result static ieee80211_rx_result
__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
......
mac80211-tests-y += module.o elems.o mac80211-tests-y += module.o elems.o mfp.o
obj-$(CONFIG_MAC80211_KUNIT_TEST) += mac80211-tests.o obj-$(CONFIG_MAC80211_KUNIT_TEST) += mac80211-tests.o
// 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, assoc;
u8 category;
u8 stype;
u8 action;
ieee80211_rx_result result;
} 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,
.result = RX_DROP_U_UNPROT_UNICAST_PUB_ACTION,
},
{
.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,
.result = RX_CONTINUE,
},
/* protected dual of public action */
{
.desc = "protected dual: drop unicast from unknown peer",
.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",
.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",
.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",
.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",
.stype = IEEE80211_STYPE_ACTION,
.category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION,
.action = WLAN_PUB_ACTION_DSE_ENABLEMENT,
.unicast = true,
.sta = true,
.mfp = true,
.result = RX_DROP_U_UNPROT_DUAL,
},
{
.desc = "protected dual: drop undecrypted multicast with MFP",
.stype = IEEE80211_STYPE_ACTION,
.category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION,
.action = WLAN_PUB_ACTION_DSE_ENABLEMENT,
.unicast = false,
.sta = true,
.mfp = true,
.result = RX_DROP_U_UNPROT_DUAL,
},
{
.desc = "protected dual: accept unicast with MFP",
.stype = IEEE80211_STYPE_ACTION,
.category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION,
.action = WLAN_PUB_ACTION_DSE_ENABLEMENT,
.decrypted = true,
.unicast = true,
.sta = true,
.mfp = true,
.result = RX_CONTINUE,
},
{
.desc = "protected dual: accept multicast with MFP",
.stype = IEEE80211_STYPE_ACTION,
.category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION,
.action = WLAN_PUB_ACTION_DSE_ENABLEMENT,
.decrypted = true,
.unicast = false,
.sta = true,
.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;
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 |
params->stype),
.addr1 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
.addr2 = { 0x12, 0x22, 0x33, 0x44, 0x55, 0x66 },
/* 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);
}
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);
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));
switch (params->stype) {
case IEEE80211_STYPE_ACTION:
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,
(__force u32)ieee80211_drop_unencrypted_mgmt(&rx),
(__force u32)params->result);
}
static struct kunit_case mfp_test_cases[] = {
KUNIT_CASE_PARAM(accept_mfp, accept_mfp_gen_params),
{}
};
static struct kunit_suite mfp = {
.name = "mac80211-mfp",
.test_cases = mfp_test_cases,
};
kunit_test_suite(mfp);
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* Wireless configuration interface internals. * Wireless configuration interface internals.
* *
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * 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 #ifndef __NET_WIRELESS_CORE_H
#define __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H
...@@ -549,4 +549,15 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, ...@@ -549,4 +549,15 @@ int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev); struct wireless_dev *wdev);
void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask); 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 */ #endif /* __NET_WIRELESS_CORE_H */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/cfg80211-wext.h> #include <net/cfg80211-wext.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <kunit/visibility.h>
#include "core.h" #include "core.h"
#include "nl80211.h" #include "nl80211.h"
#include "wext-compat.h" #include "wext-compat.h"
...@@ -303,7 +304,8 @@ static size_t cfg80211_copy_elem_with_frags(const struct element *elem, ...@@ -303,7 +304,8 @@ static size_t cfg80211_copy_elem_with_frags(const struct element *elem,
return *pos - buf; return *pos - buf;
} }
static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, VISIBLE_IF_CFG80211_KUNIT size_t
cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
const u8 *subie, size_t subie_len, const u8 *subie, size_t subie_len,
u8 *new_ie, size_t new_ie_len) u8 *new_ie, size_t new_ie_len)
{ {
...@@ -413,6 +415,7 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, ...@@ -413,6 +415,7 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
return pos - new_ie; return pos - new_ie;
} }
EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_gen_new_ie);
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
const u8 *ssid, size_t ssid_len) const u8 *ssid, size_t ssid_len)
...@@ -1864,7 +1867,7 @@ __cfg80211_bss_update(struct cfg80211_registered_device *rdev, ...@@ -1864,7 +1867,7 @@ __cfg80211_bss_update(struct cfg80211_registered_device *rdev,
&hidden->hidden_list); &hidden->hidden_list);
hidden->refcount++; hidden->refcount++;
ies = (void *)rcu_dereference(new->pub.beacon_ies); ies = (void *)rcu_access_pointer(new->pub.beacon_ies);
rcu_assign_pointer(new->pub.beacon_ies, rcu_assign_pointer(new->pub.beacon_ies,
hidden->pub.beacon_ies); hidden->pub.beacon_ies);
if (ies) if (ies)
...@@ -2614,9 +2617,11 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, ...@@ -2614,9 +2617,11 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id,
return 0; return 0;
} }
static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy, static void
cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy,
struct cfg80211_inform_single_bss_data *tx_data, struct cfg80211_inform_single_bss_data *tx_data,
struct cfg80211_bss *source_bss, struct cfg80211_bss *source_bss,
const struct element *elem,
gfp_t gfp) gfp_t gfp)
{ {
struct cfg80211_inform_single_bss_data data = { struct cfg80211_inform_single_bss_data data = {
...@@ -2626,7 +2631,6 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy, ...@@ -2626,7 +2631,6 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy,
.bss_source = BSS_SOURCE_STA_PROFILE, .bss_source = BSS_SOURCE_STA_PROFILE,
}; };
struct ieee80211_multi_link_elem *ml_elem; struct ieee80211_multi_link_elem *ml_elem;
const struct element *elem;
struct cfg80211_mle *mle; struct cfg80211_mle *mle;
u16 control; u16 control;
u8 ml_common_len; u8 ml_common_len;
...@@ -2637,15 +2641,7 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy, ...@@ -2637,15 +2641,7 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy,
const u8 *pos; const u8 *pos;
u8 i; u8 i;
if (!source_bss) if (!ieee80211_mle_size_ok(elem->data + 1, elem->datalen - 1))
return;
if (tx_data->ftype != CFG80211_BSS_FTYPE_PRESP)
return;
elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK,
tx_data->ie, tx_data->ielen);
if (!elem || !ieee80211_mle_size_ok(elem->data + 1, elem->datalen - 1))
return; return;
ml_elem = (void *)elem->data + 1; ml_elem = (void *)elem->data + 1;
...@@ -2673,8 +2669,11 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy, ...@@ -2673,8 +2669,11 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy,
/* MLD capabilities and operations */ /* MLD capabilities and operations */
pos += 2; pos += 2;
/* Not included when the (nontransmitted) AP is responding itself, /*
* but defined to zero then (Draft P802.11be_D3.0, 9.4.2.170.2) * The MLD ID of the reporting AP is always zero. It is set if the AP
* is part of an MBSSID set and will be non-zero for ML Elements
* relating to a nontransmitted BSS (matching the Multi-BSSID Index,
* Draft P802.11be_D3.2, 35.3.4.2)
*/ */
if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MLD_ID)) { if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MLD_ID)) {
mld_id = *pos; mld_id = *pos;
...@@ -2817,6 +2816,25 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy, ...@@ -2817,6 +2816,25 @@ static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy,
kfree(mle); kfree(mle);
} }
static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy,
struct cfg80211_inform_single_bss_data *tx_data,
struct cfg80211_bss *source_bss,
gfp_t gfp)
{
const struct element *elem;
if (!source_bss)
return;
if (tx_data->ftype != CFG80211_BSS_FTYPE_PRESP)
return;
for_each_element_extid(elem, WLAN_EID_EXT_EHT_MULTI_LINK,
tx_data->ie, tx_data->ielen)
cfg80211_parse_ml_elem_sta_data(wiphy, tx_data, source_bss,
elem, gfp);
}
struct cfg80211_bss * struct cfg80211_bss *
cfg80211_inform_bss_data(struct wiphy *wiphy, cfg80211_inform_bss_data(struct wiphy *wiphy,
struct cfg80211_inform_bss *data, struct cfg80211_inform_bss *data,
......
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 obj-$(CONFIG_CFG80211_KUNIT_TEST) += cfg80211-tests.o
This diff is collapsed.
// 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);
}
/* 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 */
...@@ -980,7 +980,63 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb, ...@@ -980,7 +980,63 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
} }
} }
/* The default mapping as defined Section 2.3 in RFC8325: The three
* Most Significant Bits (MSBs) of the DSCP are used as the
* corresponding L2 markings.
*/
ret = dscp >> 5; ret = dscp >> 5;
/* Handle specific DSCP values for which the default mapping (as
* described above) doesn't adhere to the intended usage of the DSCP
* value. See section 4 in RFC8325. Specifically, for the following
* Diffserv Service Classes no update is needed:
* - Standard: DF
* - Low Priority Data: CS1
* - Multimedia Streaming: AF31, AF32, AF33
* - Multimedia Conferencing: AF41, AF42, AF43
* - Network Control Traffic: CS7
* - Real-Time Interactive: CS4
*/
switch (dscp >> 2) {
case 10:
case 12:
case 14:
/* High throughput data: AF11, AF12, AF13 */
ret = 0;
break;
case 16:
/* Operations, Administration, and Maintenance and Provisioning:
* CS2
*/
ret = 0;
break;
case 18:
case 20:
case 22:
/* Low latency data: AF21, AF22, AF23 */
ret = 3;
break;
case 24:
/* Broadcasting video: CS3 */
ret = 4;
break;
case 40:
/* Signaling: CS5 */
ret = 5;
break;
case 44:
/* Voice Admit: VA */
ret = 6;
break;
case 46:
/* Telephony traffic: EF */
ret = 6;
break;
case 48:
/* Network Control Traffic: CS6 */
ret = 7;
break;
}
out: out:
return array_index_nospec(ret, IEEE80211_NUM_TIDS); return array_index_nospec(ret, IEEE80211_NUM_TIDS);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment